Cover a couple of more cases on data track runt packet handling. (#4741)

* Cover a couple of more cases on data track runt packet handling.

* Guard data track header parser against extensions-size integer wraparound.

Widen the extensions-size arithmetic to int so a 0xFFFF wire value no
longer wraps in uint16, and reject any packet whose computed hdrSize
exceeds the buffer before slicing the payload.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Raja Subramanian
2026-08-11 18:25:10 +05:30
committed by GitHub
co-authored by Claude Opus 4.8
parent d279899b7c
commit c4c356f6ca
2 changed files with 47 additions and 3 deletions
+12 -3
View File
@@ -126,11 +126,14 @@ func (h *Header) Unmarshal(buf []byte) (int, error) {
h.Timestamp = binary.BigEndian.Uint32(buf[timestampOffset : timestampOffset+timestampLength])
if h.HasExtensions {
extensionsSize := (binary.BigEndian.Uint16(buf[extensionsSizeOffset:extensionsSizeOffset+extensionsSizeLength])+1)*4 - extensionsSizeLength
if len(buf) < extensionsSizeOffset+extensionsSizeLength {
return 0, fmt.Errorf("%w: %d < %d", errHeaderSizeInsufficient, len(buf), extensionsSizeOffset+extensionsSizeLength)
}
extensionsSize := (int(binary.BigEndian.Uint16(buf[extensionsSizeOffset:extensionsSizeOffset+extensionsSizeLength]))+1)*4 - extensionsSizeLength
hdrSize += extensionsSizeLength
extensionHeaderSize := extensionIDLength + extensionSizeLength
remainingSize := int(extensionsSize)
remainingSize := extensionsSize
idx := extensionsSizeOffset + extensionsSizeLength
for remainingSize != 0 {
// read extension header
@@ -140,6 +143,9 @@ func (h *Header) Unmarshal(buf []byte) (int, error) {
id := buf[idx]
if id == 0 {
// end of extensions, padding has started
if len(buf[idx:]) < remainingSize {
return 0, fmt.Errorf("%w: %d/%d < %d", errExtensionSizeInsufficient, remainingSize, len(buf[idx:]), remainingSize)
}
hdrSize += remainingSize
break
}
@@ -163,7 +169,7 @@ func (h *Header) Unmarshal(buf []byte) (int, error) {
idx += size
hdrSize += size
}
h.ExtensionsSize = extensionsSize - uint16(remainingSize)
h.ExtensionsSize = uint16(extensionsSize - remainingSize)
}
return hdrSize, nil
@@ -271,6 +277,9 @@ func (p *Packet) Unmarshal(buf []byte) error {
if err != nil {
return err
}
if hdrSize > len(buf) {
return fmt.Errorf("%w: %d < %d", errBufferSizeInsufficient, len(buf), hdrSize)
}
p.Payload = buf[hdrSize:]
return nil
+35
View File
@@ -256,4 +256,39 @@ func TestPacket(t *testing.T) {
err = unmarshaled.Unmarshal(badPacket)
require.Error(t, err)
})
t.Run("oversized extension padding does not panic", func(t *testing.T) {
var unmarshaled Packet
// HasExtensions set, extensionsSize describes more bytes than present,
// terminated by a 0x00 padding id -> hdrSize would exceed len(buf)
badPacket := []byte{
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}
err := unmarshaled.Unmarshal(badPacket)
require.Error(t, err)
})
t.Run("extensions size wraparound does not panic", func(t *testing.T) {
var unmarshaled Packet
// 0xFFFF extensions-size field wraps (raw+1)*4 uint16 arithmetic to a huge
// remainingSize; the 0x00 padding id must not push hdrSize past len(buf)
badPacket := []byte{
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00,
}
err := unmarshaled.Unmarshal(badPacket)
require.Error(t, err)
})
t.Run("truncated extensions size field does not panic", func(t *testing.T) {
var unmarshaled Packet
// HasExtensions set but buffer too short to hold the extensionsSize field
badPacket := []byte{
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
}
err := unmarshaled.Unmarshal(badPacket)
require.Error(t, err)
})
}