Skip to content

TransportLayerCC / CCFeedbackReport: Marshal panics on packets over the uint16 length limit #234

Closed

Description

@sollniss

Marshal computes the packet size in a uint16, which wraps for large packets. The buffer is then allocated too small and Marshal panics instead of returning an error.

TransportLayerCC: packetLen() wraps above 65535 bytes.

rtcp/transport_layer_cc.go

Lines 365 to 377 in 2599616

func (t *TransportLayerCC) packetLen() uint16 {
//nolint:gocognit,cyclop
n := uint16(headerLength + packetChunkOffset + len(t.PacketChunks)*2) //nolint:gosec // G115
for _, d := range t.RecvDeltas {
if d.Type == TypeTCCPacketReceivedSmallDelta {
n++
} else {
n += 2
}
}
return n
}

CCFeedbackReport: Header().Length wraps above 262144 bytes, and Marshal sizes its buffer from it.

rtcp/rfc8888.go

Lines 137 to 149 in 2599616

Length: uint16(b.MarshalSize()/4 - 1), //nolint:gosec // G115
}
}
// Marshal encodes the Congestion Control Feedback Report in binary.
func (b CCFeedbackReport) Marshal() ([]byte, error) {
header := b.Header()
headerBuf, err := header.Marshal()
if err != nil {
return nil, err
}
length := 4 * (int(header.Length) + 1)
buf := make([]byte, length)

Reproducer

package main

import (
	"fmt"

	"github.com/pion/rtcp"
)

func try(name string, p rtcp.Packet) {
	defer func() { fmt.Println(name, "->", recover()) }()
	p.Marshal()
}

func main() {
	// 32768 large deltas: 2 bytes each, so the packet is over 65535 bytes.
	deltas := make([]*rtcp.RecvDelta, 32768)
	for i := range deltas {
		deltas[i] = &rtcp.RecvDelta{Type: rtcp.TypeTCCPacketReceivedLargeDelta}
	}
	try("TransportLayerCC", &rtcp.TransportLayerCC{RecvDeltas: deltas})

	// 8 blocks of 16384 metric blocks each: over 262144 bytes.
	ccfb := &rtcp.CCFeedbackReport{}
	for range 8 {
		ccfb.ReportBlocks = append(ccfb.ReportBlocks, rtcp.CCFeedbackReportBlock{
			MetricBlocks: make([]rtcp.CCFeedbackMetricBlock, 16384),
		})
	}
	try("CCFeedbackReport", ccfb)
}
TransportLayerCC -> runtime error: slice bounds out of range [18:16]
CCFeedbackReport -> runtime error: slice bounds out of range [32784:76]

The panics are at transport_layer_cc.go:446 and rfc8888.go:158.

Expected: Marshal returns an error when the packet does not fit the length field (similar to #164).

These two panics can't be triggered remotely, so this should be low priority. My last PR to pion/rtp seemed to contain a correctness bug, so I'll refrain from trying to fix this myself. :P

Found with a static analyzer, reproducer is AI generated.

Activity

  1. JoTurk commented on Oct 14, 2026

    @JoTurk
    Member

    These two panics can't be triggered remotely, so this should be low priority. My last PR to pion/rtp seemed to contain a correctness bug, so I'll refrain from trying to fix this myself. :P

    Please don't make this block you from sending patches, review and follow up fixes exist for this reason :)

  2. sollniss commented on Oct 14, 2026

    @sollniss
    Author

    Alright I'll keep that in mind if I find anything else :)

    Looks like someone already made a PR for this ❤

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions