You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
std: ReadTlvStream accepts a huge TLV-LENGTH, desyncing the stream or crashing the process #211
ReadTlvStream in std/utils/io/stream_read.go computes the frame size as typ.EncodingLength() + len.EncodingLength() + int(len). A TLV-LENGTH above math.MaxInt64 wraps negative in the int conversion. The framer then treats the wrapped value as a valid frame size: it delivers garbage bytes to the caller from the wrong offset and loses stream synchronization (observed: one crafted block turned into 34 bogus frames), and for lengths near 2^63 the size goes negative enough that slicing the buffer panics with an out-of-range error (verified: slice bounds out of range [:-9223372036854775795]).
Impact
ReadTlvStream is the receive loop for every stream transport: unicast TCP, unicast and multicast UDP, Unix stream faces, and the client-side StreamFace used by apps built on this library. A malformed or malicious peer on any of these can desync the face or crash the whole process.
Reproduction
Feed the framer a valid 3-byte frame followed by a block with type 0x64 and TLV-LENGTH 0xFFFFFFFFFFFFFFFF. Expected: the stream aborts with an error after the valid frame. Actual: dozens of garbage frames are delivered. With TLV-LENGTH 0x8000000000000000 the process panics.
Proposed fix
Reject any block whose declared length exceeds the receive buffer capacity (8 * MaxNDNPacketSize); such a block can never complete anyway, and the guard keeps the size computation out of the overflow range. PR includes a regression test that fails before the fix and passes after.
Repro evidence (Go 1.26.6, linux/amd64, ndnd main @ d51682b).
Stream containing one valid 3-byte frame, then a block with type 0x64 and TLV-LENGTH 0xFFFFFFFFFFFFFFFF, run against unpatched main:
$ go test ./std/utils/io/ -run TestReadTlvStreamRejectsHugeLength -v
=== RUN TestReadTlvStreamRejectsHugeLength
stream_read_test.go:27:
Error: An error is expected but got nil.
Messages: oversized TLV-LENGTH must abort the stream
stream_read_test.go:28:
Error: Not equal:
expected: 1
actual : 34
Messages: only the valid frame may be delivered
--- FAIL: TestReadTlvStreamRejectsHugeLength (0.00s)
FAIL
The crafted block desyncs the framer into delivering 34 bogus frames. With TLV-LENGTH 0x8000000000000000 the same path panics the process:
$ go test ./std/utils/io/ -run TestReadTlvStreamPanicOnHugeLength -v
--- FAIL: TestReadTlvStreamPanicOnHugeLength (0.00s)
panic: runtime error: slice bounds out of range [:-9223372036854775795] [recovered, repanicked]
Against the fix branch (fix/tlv-stream-length-overflow):
$ go test ./std/utils/io/ -run TestReadTlvStreamRejectsHugeLength -v
=== RUN TestReadTlvStreamRejectsHugeLength
--- PASS: TestReadTlvStreamRejectsHugeLength (0.00s)
PASS
ok github.com/named-data/ndnd/std/utils/io 0.003s
Activity
Harsh23Kashyap commentedon Sep 16, 2026
Repro evidence (Go 1.26.6, linux/amd64, ndnd main @ d51682b).
Stream containing one valid 3-byte frame, then a block with type 0x64 and TLV-LENGTH 0xFFFFFFFFFFFFFFFF, run against unpatched main:
The crafted block desyncs the framer into delivering 34 bogus frames. With TLV-LENGTH 0x8000000000000000 the same path panics the process:
Against the fix branch (fix/tlv-stream-length-overflow):