Skip to content

Commit fa5b35e

Browse files
committed
Fix padding overflow with PacketFactory
RTP padding overflow is now handled, instead of catching a panic. pion/webrtc#3148
1 parent 7914551 commit fa5b35e

File tree

3 files changed

+55
-1
lines changed

3 files changed

+55
-1
lines changed

internal/rtpbuffer/errors.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ var (
1212
errPacketReleased = errors.New("could not retain packet, already released")
1313
errFailedToCastHeaderPool = errors.New("could not access header pool, failed cast")
1414
errFailedToCastPayloadPool = errors.New("could not access payload pool, failed cast")
15+
errPaddingOverflow = errors.New("padding size exceeds payload size")
1516
)

internal/rtpbuffer/packet_factory.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ func (m *PacketFactoryCopy) NewPacket(
8484
}
8585
}
8686

87-
if rtxSsrc != 0 && rtxPayloadType != 0 {
87+
if rtxSsrc != 0 && rtxPayloadType != 0 { //nolint:nestif
8888
if payload == nil {
8989
retainablePacket.buffer, ok = m.payloadPool.Get().(*[]byte)
9090
if !ok {
@@ -105,6 +105,11 @@ func (m *PacketFactoryCopy) NewPacket(
105105
if retainablePacket.header.Padding && retainablePacket.payload != nil && len(retainablePacket.payload) > 0 {
106106
paddingLength := int(retainablePacket.payload[len(retainablePacket.payload)-1])
107107
retainablePacket.header.Padding = false
108+
109+
if paddingLength > len(retainablePacket.payload) {
110+
return nil, errPaddingOverflow
111+
}
112+
108113
retainablePacket.payload = (*retainablePacket.buffer)[:len(retainablePacket.payload)-paddingLength]
109114
}
110115
}

internal/rtpbuffer/rtpbuffer_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package rtpbuffer
55

66
import (
7+
"bytes"
78
"testing"
89

910
"github.com/pion/rtp"
@@ -218,3 +219,50 @@ func TestRTPBuffer_Overridden_WithRTX_NILPayload(t *testing.T) {
218219

219220
require.Nil(t, sb.Get(1))
220221
}
222+
223+
func TestRTPBuffer_Padding(t *testing.T) {
224+
pm := NewPacketFactoryCopy()
225+
sb, err := NewRTPBuffer(1)
226+
require.NoError(t, err)
227+
require.Equal(t, uint16(1), sb.size)
228+
229+
t.Run("valid padding is stripped", func(t *testing.T) {
230+
origPayload := []byte{116, 101, 115, 116}
231+
expected := []byte{0, 1, 116, 101, 115, 116}
232+
233+
padLen := 120
234+
padded := make([]byte, 0)
235+
padded = append(padded, origPayload...)
236+
padded = append(padded, bytes.Repeat([]byte{0}, padLen-1)...)
237+
padded = append(padded, byte(padLen))
238+
239+
pkt, err := pm.NewPacket(&rtp.Header{
240+
SequenceNumber: 1,
241+
Padding: true,
242+
}, padded, 1, 1)
243+
require.NoError(t, err)
244+
245+
sb.Add(pkt)
246+
247+
retrieved := sb.Get(1)
248+
require.NotNil(t, retrieved)
249+
defer retrieved.Release()
250+
251+
require.False(t, retrieved.Header().Padding, "P-bit should be cleared after trimming")
252+
253+
actual := retrieved.Payload()
254+
require.Equal(t, len(expected), len(actual), "payload length after trimming")
255+
require.Equal(t, expected, actual, "payload content after trimming")
256+
})
257+
258+
t.Run("overflow padding returns io.ErrShortBuffer", func(t *testing.T) {
259+
overflow := []byte{0, 1, 200}
260+
261+
_, err := pm.NewPacket(&rtp.Header{
262+
SequenceNumber: 2,
263+
Padding: true,
264+
}, overflow, 1, 1)
265+
266+
require.ErrorIs(t, err, errPaddingOverflow, "factory should reject invalid padding")
267+
})
268+
}

0 commit comments

Comments
 (0)