Skip to content

Out-of-bounds read in RspConnector::DecodeRLE on malformed RLE runs #1170

Description

@xusheng6

RspConnector::DecodeRLE does not bounds check the '*' run-length branch:

else if (data.m_data[index] == '*')
{
    auto repeat = data.m_data[index + 1] - 29;   // index + 1 may be past the end
    auto last_char = result[result.size() - 1];  // result may be empty -> result[SIZE_MAX]

An RLE run is <char>*<count>, so it needs both a count byte after the * and a
character before it to repeat. Neither is checked.

  • A packet whose first byte is * leaves result empty, so result[result.size() - 1]
    indexes SIZE_MAX. ASan reports stack-buffer-overflow ... underflows this variable 'result'. DecodeRLE(RspData("*A")) and DecodeRLE(RspData("*")) both abort.
  • A trailing * reads m_data[index + 1] one past the buffer. DataBuffer::operator[]
    is unchecked. ASan does not flag this one because the buffer comes from BN core, which
    is not instrumented, so this part is from reading the code rather than a tool result.

This is reachable from ordinary traffic: RLE is a standard RSP feature and gdbserver uses
it to compress repeated bytes, which is common when reading module maps or zero-filled
memory. The data is entirely stub controlled.

Found by fuzzing the GDB adapter against a live Corellium stub through a mutating proxy.
The path hit was GetModuleList -> GetRemoteFile -> HostFileIO -> ReceiveRspData -> DecodeRLE.

Distinct from #1164: that is unhandled exceptions from integer parsing, and #1166 does not
touch DecodeRLE. This one is memory corruption, so a catch boundary does not help it.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions