Skip to content

Fix unbounded sysex_buffer accumulation in convert_midi_bytes_to_messages#912

Open
94xhn wants to merge 1 commit into
shorepine:mainfrom
94xhn:fix-sysex-length-bound
Open

Fix unbounded sysex_buffer accumulation in convert_midi_bytes_to_messages#912
94xhn wants to merge 1 commit into
shorepine:mainfrom
94xhn:fix-sysex-length-bound

Conversation

@94xhn

@94xhn 94xhn commented Jul 16, 2026

Copy link
Copy Markdown

Bug

convert_midi_bytes_to_messages() in src/amy_midi.c accumulates incoming sysex data bytes into sysex_buffer with no length check:

if(sysex_flag) {
    if(byte == 0xF7) {
        sysex_flag = 0;
        parse_sysex();
    } else {
        sysex_buffer[sysex_len++] = byte;   // <-- no bound check
    }
}

sysex_buffer is allocated to exactly MAX_SYSEX_BYTES (16384, defined in src/amy_midi.h). sysex_len/sysex_flag are only reset on an 0xF7 terminator or a fresh MIDI status byte (0x80-0xF7). A sysex payload longer than 16384 bytes with no intervening terminator — a legitimate large bulk sysex dump, or simply a corrupted/noisy MIDI stream that drops the terminating F7 — writes straight past the allocation and corrupts the heap.

parse_sysex() additionally writes a NUL terminator at sysex_buffer[sysex_len], so the cap needs to be MAX_SYSEX_BYTES - 1, not MAX_SYSEX_BYTES, to keep that write in-bounds too.

Fix

} else if(sysex_len < MAX_SYSEX_BYTES - 1) {
    sysex_buffer[sysex_len++] = byte;
}
// else: drop the byte -- sysex overflowed the buffer

Verification

Built a guard-page harness (VirtualAlloc + VirtualProtect PAGE_NOACCESS immediately after a MAX_SYSEX_BYTES-sized allocation) and ran the accumulation branch verbatim as it appears in the source, both before and after the fix:

  • Before the fix: feeding bytes past the 16384th one faults on the very first out-of-bounds write (index 16384) — zero slack past the real allocation size.
  • After the fix: feeding 100000 hostile bytes (no 0xF7) caps sysex_len at 16383, the guard page is never touched, and the subsequent NUL-terminator write also lands in-bounds.

Also compiled src/amy_midi.c standalone (gcc -c) with the fix — no new warnings.

convert_midi_bytes_to_messages() accumulated incoming sysex data bytes
into sysex_buffer with no length check: sysex_buffer[sysex_len++] = byte
ran unconditionally while sysex_flag was set. sysex_buffer is allocated
to exactly MAX_SYSEX_BYTES (16384). A sysex payload longer than that
with no intervening 0xF7 terminator or fresh status byte -- a large
bulk sysex dump, or simply a corrupted/noisy MIDI stream that drops the
terminating F7 -- walks straight past the allocation and corrupts the
heap.

Cap sysex_len at MAX_SYSEX_BYTES - 1 (not MAX_SYSEX_BYTES) before the
accumulation write, dropping any further bytes once the buffer is full.
The "- 1" leaves room for the NUL terminator parse_sysex() later writes
at sysex_buffer[sysex_len].
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant