Coordinated Disclosure Timeline

Project

Gstreamer

Tested Version

1.25.0.1

Details

Integer underflow in qtdemux_parse_theora_extension leading to function pointer overwrite (GHSL-2024-166)

An integer underflow has been detected in the function qtdemux_parse_theora_extension within qtdemux.c.

The vulnerability occurs due to an underflow of the gint size variable, which causes size to hold a large unintended value when cast to an unsigned integer:


static gboolean qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * xdxt){
...
   gint size;
...
   size -= 8; //Size value = -7 => 0xfffffff9 (unsigned)
...
}

This 32-bit negative value is then cast to a 64-bit unsigned integer (0xfffffffffffffffa) in a subsequent call to gst_buffer_new_and_alloc:

        buffer = gst_buffer_new_and_alloc (size);
        gst_buffer_fill (buffer, 0, buf, size);
        stream->buffers = g_slist_append (stream->buffers, buffer);

The function gst_buffer_new_allocate then attempts to allocate memory, eventually calling _sysmem_new_block.

The function _sysmem_new_block adds alignment and header size to the (unsigned) size, causing the overflow of the ‘slice_size’ variable. As a result, only 0x89 bytes are allocated, despite the large input size:

static GstMemorySystem *_sysmem_new_block (GstMemoryFlags flags, gsize maxsize, gsize align, gsize offset, gsize size){
...
  /* ensure configured alignment */
  align |= gst_memory_alignment;
  /* allocate more to compensate for alignment */
  maxsize += align;
  /* alloc header and data in one block */
  slice_size = sizeof (GstMemorySystem) + maxsize; => 0x89!!!!

  mem = g_malloc (slice_size);
...

When the following memcpy call occurs in gst_buffer_fill, the data from the input file will overwrite the content of the GstMapInfo info structure:

gsize gst_buffer_fill (GstBuffer * buffer, gsize offset, gconstpointer src, gsize size){
...
   memcpy ((guint8 *) info.data + offset, ptr, tocopy);
...
}

Finally, during the call to gst_memory_unmap, the overwritten memory may cause a function pointer hijack, as the mem->allocator->mem_unmap_full function is called with a corrupted pointer:

void gst_memory_unmap (GstMemory * mem, GstMapInfo * info){
...
  if (mem->allocator->mem_unmap_full)
    mem->allocator->mem_unmap_full (mem, info);
  else
    mem->allocator->mem_unmap (mem);
...
}

This function pointer overwrite could allow an attacker to alter the execution flow of the program, leading to arbitrary code execution.

Impact

This vulnerability could allow an attacker to hijack the execution flow, potentially leading to code execution.

CVE

Credit

This issue was discovered and reported by GHSL team member @antonio-morales (Antonio Morales).

Contact

You can contact the GHSL team at securitylab@github.com, please include a reference to GHSL-2024-166 in any communication regarding this issue.