There is a bug in the instrument parsing code in LoaderXM::load that can cause a stack buffer overflow when the program is supplied with a malformed XM module file. This can be abused by an attacker to corrupt the stack, control program execution flow and gain code execution.
Execution log
➜ ~/MilkyTracker/build/src/tracker git:(master) ✗ ./milkytracker crash.xm
Available Renderers: opengl opengles2 software
Vendor : Mesa/X.org
Renderer : llvmpipe (LLVM 12.0.0, 256 bits)
Version : OpenGL ES 3.2 Mesa 21.0.3
SDL: Minimum window size set to 640x480.
SDL: Using accelerated renderer.
SDL: Renderer supports rendering to texture.
SDL: Using audio driver: pulseaudio
SDL: Buffer size = 2048 samples (requested 2048)
*** stack smashing detected ***: terminated
Crashed with signal 6
Please submit a bug report stating exactly what you were doing at the time of the crash, as well as the above signal number. Also note if it is possible to reproduce this crash.
A backup has been saved to /home/user/BACKUP10.XM
[1] 3242 abort ./milkytracker crash.xm
During loading an instrument header, there is a check that instr[y].size < 29. Some lines later, instr[y].size - 4 is used as length for f.read(). If size, an unsigned int directly controllable by the file format, is set to 0, it will underflow (and become max unsigned int - 3). Then, the program will read the remainder of the file file to buffer and corrupt the stack with arbitrary attacker-controlled data.
Fix
A quick and dirty fix would be to change the if condition to instr[y].size - 4 < 29.
Description
There is a bug in the instrument parsing code in
LoaderXM::load
that can cause a stack buffer overflow when the program is supplied with a malformed XM module file. This can be abused by an attacker to corrupt the stack, control program execution flow and gain code execution.Execution log
Reproduction
crash.xm contents (hexdump):
(You can use
xxd -r crash.hexdump > crash.xm
to get the binary file).Analysis
In https://github.com/milkytracker/MilkyTracker/blob/master/src/milkyplay/LoaderXM.cpp#L481
During loading an instrument header, there is a check that
instr[y].size < 29
. Some lines later,instr[y].size - 4
is used as length forf.read()
. Ifsize
, an unsigned int directly controllable by the file format, is set to 0, it will underflow (and become max unsigned int - 3). Then, the program will read the remainder of the file file tobuffer
and corrupt the stack with arbitrary attacker-controlled data.Fix
A quick and dirty fix would be to change the
if
condition toinstr[y].size - 4 < 29
.