Filed here because the security-report address in SLikeNet's readme (support@slikesoft.com, section 6.2) is
no longer deliverable: mail to it bounces. Proof-of-concept harnesses and full AddressSanitizer traces are
withheld from this public issue and are available to the maintainer privately on request.
SLikeNet's split-packet reassembly (Source/src/ReliabilityLayer.cpp, the SplitPacketSort path, which is
the default because PREALLOCATE_LARGE_MESSAGES is 0) carries three RakNet-lineage memory-safety defects.
All three were reproduced against master (d5f775d) built Release with AddressSanitizer; the reassembly
core is unchanged since 2018-06-22.
1. Out-of-bounds write from inconsistent fragments. SplitPacketSort::Add indexes m_data with the
wire splitPacketIndex; the only check against the allocated size is RakAssert(splitPacketIndex < m_allocationSize)
(:299), which defines.h:116 makes empty in release. The array is sized from the first fragment of a
channel (Preallocate, :259-260, looked up by splitPacketId alone at :3114), and a later fragment with
the same id is not checked for a matching count before Add (:3212). The per-packet check at :2835 only
compares a fragment's own index against its own count, so a second fragment declaring a large count and a
large index passes it and writes outside the array. Add reads the slot (:303) before writing it (:304),
so it is an OOB read then an OOB write of a heap pointer.
Reproduced: ASan heap-buffer-overflow at ReliabilityLayer.cpp:303, array from :260.
2. Unbounded allocation from a wire count. SplitPacketSort::Preallocate (:256-266) sizes an
allocation directly from a single fragment's splitPacketCount with no ceiling, and passes it through an
(int) cast: m_data = OP_NEW_ARRAY<InternalPacket*>((int)m_allocationSize, ...) (:260). One fragment with
splitPacketCount = 0x7FFFFFFF requests roughly 17 GB; one with 0x80000000 becomes negative at the cast
and the size computation wraps.
Reproduced: 17 GB requested from one packet; 0x80000000 gives ASan allocation-size-too-big at :260.
3. Heap overflow from a bit-to-byte rounding mismatch. BuildPacketFromSplitPacketList (:3260) sizes
the reassembly buffer by rounding the summed dataBitLength up to bytes once (:3279), then in the copy
loop rounds each fragment up independently (:3286) with the destination taken from a bit-accumulated
offset. Two 12-bit fragments give a 3-byte allocation but 4 bytes written: a one-byte overflow with an
attacker byte.
Reproduced: ASan heap-buffer-overflow WRITE at ReliabilityLayer.cpp:3286, buffer from :3279.
Reachability. These sit on the split-packet reassembly path in the RakNet-lineage receive code, below
application-level authentication (the same position as in the CrabNet sibling). A connected peer that has
completed the plaintext offline handshake reaches them.
Suggested fixes
- In
SplitPacketSort::Add, bound splitPacketIndex against m_allocationSize with a real check that
releases the packet, not a RakAssert; and in InsertIntoSplitPacketList, reject a later fragment whose
splitPacketCount disagrees with the size the channel was allocated at.
- Cap
splitPacketCount against an MTU-derived bound before Preallocate, and remove the (int) cast (or
validate before it) so a large count cannot become negative.
- In
BuildPacketFromSplitPacketList, compute the copy offset and each fragment's length from the same
rounding, or reject any non-final fragment whose dataBitLength is not a multiple of eight.
Systemically, RakAssert should not be the sole guard on any attacker-controlled index on the parse path,
and should fail closed there in release rather than compiling away.
Prior art and scope. The same class is open upstream since 2020 (RakNet issue facebookarchive#143,
facebookarchive#143) and covered for a sibling implementation by RakLib
advisory GHSA-v8hj-23c3-8w33 (GHSA-v8hj-23c3-8w33). The
CrabNet fork carries the same three defects and is reported separately. These are RakNet-lineage issues
inherited from common ancestry, not novel.
Filed here because the security-report address in SLikeNet's readme (
support@slikesoft.com, section 6.2) isno longer deliverable: mail to it bounces. Proof-of-concept harnesses and full AddressSanitizer traces are
withheld from this public issue and are available to the maintainer privately on request.
SLikeNet's split-packet reassembly (
Source/src/ReliabilityLayer.cpp, theSplitPacketSortpath, which isthe default because
PREALLOCATE_LARGE_MESSAGESis 0) carries three RakNet-lineage memory-safety defects.All three were reproduced against
master(d5f775d) built Release with AddressSanitizer; the reassemblycore is unchanged since 2018-06-22.
1. Out-of-bounds write from inconsistent fragments.
SplitPacketSort::Addindexesm_datawith thewire
splitPacketIndex; the only check against the allocated size isRakAssert(splitPacketIndex < m_allocationSize)(
:299), whichdefines.h:116makes empty in release. The array is sized from the first fragment of achannel (
Preallocate,:259-260, looked up bysplitPacketIdalone at:3114), and a later fragment withthe same id is not checked for a matching count before
Add(:3212). The per-packet check at:2835onlycompares a fragment's own index against its own count, so a second fragment declaring a large count and a
large index passes it and writes outside the array.
Addreads the slot (:303) before writing it (:304),so it is an OOB read then an OOB write of a heap pointer.
2. Unbounded allocation from a wire count.
SplitPacketSort::Preallocate(:256-266) sizes anallocation directly from a single fragment's
splitPacketCountwith no ceiling, and passes it through an(int)cast:m_data = OP_NEW_ARRAY<InternalPacket*>((int)m_allocationSize, ...)(:260). One fragment withsplitPacketCount = 0x7FFFFFFFrequests roughly 17 GB; one with0x80000000becomes negative at the castand the size computation wraps.
3. Heap overflow from a bit-to-byte rounding mismatch.
BuildPacketFromSplitPacketList(:3260) sizesthe reassembly buffer by rounding the summed
dataBitLengthup to bytes once (:3279), then in the copyloop rounds each fragment up independently (
:3286) with the destination taken from a bit-accumulatedoffset. Two 12-bit fragments give a 3-byte allocation but 4 bytes written: a one-byte overflow with an
attacker byte.
Reachability. These sit on the split-packet reassembly path in the RakNet-lineage receive code, below
application-level authentication (the same position as in the CrabNet sibling). A connected peer that has
completed the plaintext offline handshake reaches them.
Suggested fixes
SplitPacketSort::Add, boundsplitPacketIndexagainstm_allocationSizewith a real check thatreleases the packet, not a
RakAssert; and inInsertIntoSplitPacketList, reject a later fragment whosesplitPacketCountdisagrees with the size the channel was allocated at.splitPacketCountagainst an MTU-derived bound beforePreallocate, and remove the(int)cast (orvalidate before it) so a large count cannot become negative.
BuildPacketFromSplitPacketList, compute the copy offset and each fragment's length from the samerounding, or reject any non-final fragment whose
dataBitLengthis not a multiple of eight.Systemically,
RakAssertshould not be the sole guard on any attacker-controlled index on the parse path,and should fail closed there in release rather than compiling away.
Prior art and scope. The same class is open upstream since 2020 (RakNet issue facebookarchive#143,
facebookarchive#143) and covered for a sibling implementation by RakLib
advisory GHSA-v8hj-23c3-8w33 (GHSA-v8hj-23c3-8w33). The
CrabNet fork carries the same three defects and is reported separately. These are RakNet-lineage issues
inherited from common ancestry, not novel.