Skip to content

[BUG] Heap Buffer Overflow in DivPlatformYM2610::dispatch #2286

@0xdd96

Description

@0xdd96

To Reproduce

Environment

  • OS: Ubuntu 22.04 LTS
  • Compiler: gcc version 11.4.0
  • version: latest commit 5eae178

poc: poc

Steps to reproduce the behavior:

CFLAGS="-g -O0" CXXFLAGS="-g -O0" cmake ..
make
run valgrind ./furnace -console -vgmout out.vgm $POC

Expected behavior

user@c3ae4d510abb:$ valgrind ./furnace -console -vgmout out.vgm $POC
==2476279== Invalid read of size 2
==2476279==    at 0x7C9C3E: DivPlatformYM2610::dispatch(DivCommand) (ym2610.cpp:1434)
==2476279==    by 0x6CE1DB: DivEngine::dispatchCmd(DivCommand) (playback.cpp:436)
==2476279==    by 0x6CE6D4: DivEngine::perSystemPostEffect(int, unsigned char, unsigned char) (playback.cpp:472)
==2476279==    by 0x6D60A0: DivEngine::processRow(int, bool) (playback.cpp:1296)
==2476279==    by 0x6D6BE8: DivEngine::nextRow() (playback.cpp:1399)
==2476279==    by 0x6D887B: DivEngine::nextTick(bool, bool) (playback.cpp:1658)
==2476279==    by 0x734D27: DivEngine::saveVGM(bool*, bool, int, bool, bool, int) (vgmOps.cpp:2604)
==2476279==    by 0x9362C9: main (main.cpp:865)
==2476279==  Address 0x6802ac8 is 0 bytes after a block of size 141,960 alloc'd
==2476279==    at 0x4849013: operator new(unsigned long) (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==2476279==    by 0x66760D: DivDispatchContainer::init(DivSystem, DivEngine*, int, double, DivConfig const&, bool) (dispatchContainer.cpp:362)
==2476279==    by 0x693CBD: DivEngine::initDispatch(bool) (engine.cpp:3689)
==2476279==    by 0x6971D4: DivEngine::init() (engine.cpp:4082)
==2476279==    by 0x935F19: main (main.cpp:821)
==2476279==

Here is some debug info in gdb:

Thread 1 "furnace" hit Breakpoint 1, DivPlatformYM2610::dispatch (this=0x55555743ed10, c=...) at ym2610.cpp:1434
1434              unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
(gdb) p c.chan
$1 = 12 '\f'
(gdb) p chanOffs
$2 = {1, 2, 257, 258}
(gdb) p psgChanOffs
$3 = 4
(gdb) p chanOffs[12]
$4 = 33

It seems that c.chan is not checked against psgChanOffs.

case DIV_CMD_FM_RS: {
if (c.value<0) {
for (int i=0; i<4; i++) {
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
op.rs=c.value2&3;
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
}
} else if (c.value<4) {
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
op.rs=c.value2&3;
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
}
break;
}

A similar overflow issue also occurs at line 1520. Here is the poc.

case DIV_CMD_FM_D2R: {
if (c.value<0) {
for (int i=0; i<4; i++) {
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
op.d2r=c.value2&31;
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
}
} else if (c.value<4) {
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
op.d2r=c.value2&31;
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
}
break;
}

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingcriticalRequires urgent fixing

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions