Skip to content

Commit

Permalink
Fix multiple crashes when using VP9 depacketizer
Browse files Browse the repository at this point in the history
Multiple optional fields of the VP9 RTP header are read regardless of
the buffer size. This can easily lead to multiple crashes. This PR add
the necessary checks in order to avoid crashes.
  • Loading branch information
aler9 committed Feb 12, 2023
1 parent cf0f407 commit 9f0d145
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 25 deletions.
79 changes: 54 additions & 25 deletions codecs/vp9_packet.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,12 +207,15 @@ func (p *VP9Packet) Unmarshal(packet []byte) ([]byte, error) {

// Picture ID:
//
// +-+-+-+-+-+-+-+-+
// +-+-+-+-+-+-+-+-+
//
// I: |M| PICTURE ID | M:0 => picture id is 7 bits.
// +-+-+-+-+-+-+-+-+ M:1 => picture id is 15 bits.
//
// +-+-+-+-+-+-+-+-+ M:1 => picture id is 15 bits.
//
// M: | EXTENDED PID |
// +-+-+-+-+-+-+-+-+
//
// +-+-+-+-+-+-+-+-+
func (p *VP9Packet) parsePictureID(packet []byte, pos int) (int, error) {
if len(packet) <= pos {
return pos, errShortPacket
Expand Down Expand Up @@ -245,10 +248,11 @@ func (p *VP9Packet) parseLayerInfo(packet []byte, pos int) (int, error) {

// Layer indices (flexible mode):
//
// +-+-+-+-+-+-+-+-+
// +-+-+-+-+-+-+-+-+
//
// L: | T |U| S |D|
// +-+-+-+-+-+-+-+-+
//
// +-+-+-+-+-+-+-+-+
func (p *VP9Packet) parseLayerInfoCommon(packet []byte, pos int) (int, error) {
if len(packet) <= pos {
return pos, errShortPacket
Expand All @@ -269,12 +273,13 @@ func (p *VP9Packet) parseLayerInfoCommon(packet []byte, pos int) (int, error) {

// Layer indices (non-flexible mode):
//
// +-+-+-+-+-+-+-+-+
// +-+-+-+-+-+-+-+-+
//
// L: | T |U| S |D|
// +-+-+-+-+-+-+-+-+
// | TL0PICIDX |
// +-+-+-+-+-+-+-+-+
//
// +-+-+-+-+-+-+-+-+
// | TL0PICIDX |
// +-+-+-+-+-+-+-+-+
func (p *VP9Packet) parseLayerInfoNonFlexibleMode(packet []byte, pos int) (int, error) {
if len(packet) <= pos {
return pos, errShortPacket
Expand All @@ -287,11 +292,12 @@ func (p *VP9Packet) parseLayerInfoNonFlexibleMode(packet []byte, pos int) (int,

// Reference indices:
//
// +-+-+-+-+-+-+-+-+ P=1,F=1: At least one reference index
// +-+-+-+-+-+-+-+-+ P=1,F=1: At least one reference index
//
// P,F: | P_DIFF |N| up to 3 times has to be specified.
// +-+-+-+-+-+-+-+-+ N=1: An additional P_DIFF follows
// current P_DIFF.
//
// +-+-+-+-+-+-+-+-+ N=1: An additional P_DIFF follows
// current P_DIFF.
func (p *VP9Packet) parseRefIndices(packet []byte, pos int) (int, error) {
for {
if len(packet) <= pos {
Expand All @@ -313,24 +319,30 @@ func (p *VP9Packet) parseRefIndices(packet []byte, pos int) (int, error) {

// Scalability structure (SS):
//
// +-+-+-+-+-+-+-+-+
// +-+-+-+-+-+-+-+-+
//
// V: | N_S |Y|G|-|-|-|
// +-+-+-+-+-+-+-+-+ -|
//
// +-+-+-+-+-+-+-+-+ -|
//
// Y: | WIDTH | (OPTIONAL) .
// + + .
// | | (OPTIONAL) .
// +-+-+-+-+-+-+-+-+ . N_S + 1 times
// | HEIGHT | (OPTIONAL) .
// + + .
// | | (OPTIONAL) .
// +-+-+-+-+-+-+-+-+ -|
// - + .
// | | (OPTIONAL) .
// +-+-+-+-+-+-+-+-+ . N_S + 1 times
// | HEIGHT | (OPTIONAL) .
// - + .
// | | (OPTIONAL) .
// +-+-+-+-+-+-+-+-+ -|
//
// G: | N_G | (OPTIONAL)
// +-+-+-+-+-+-+-+-+ -|
//
// +-+-+-+-+-+-+-+-+ -|
//
// N_G: | T |U| R |-|-| (OPTIONAL) .
// +-+-+-+-+-+-+-+-+ -| . N_G times
// | P_DIFF | (OPTIONAL) . R times .
// +-+-+-+-+-+-+-+-+ -| -|
//
// +-+-+-+-+-+-+-+-+ -| . N_G times
// | P_DIFF | (OPTIONAL) . R times .
// +-+-+-+-+-+-+-+-+ -| -|
func (p *VP9Packet) parseSSData(packet []byte, pos int) (int, error) {
if len(packet) <= pos {
return pos, errShortPacket
Expand All @@ -348,6 +360,10 @@ func (p *VP9Packet) parseSSData(packet []byte, pos int) (int, error) {
p.Width = make([]uint16, NS)
p.Height = make([]uint16, NS)
for i := 0; i < int(NS); i++ {
if len(packet) <= (pos + 3) {
return pos, errShortPacket
}

p.Width[i] = uint16(packet[pos])<<8 | uint16(packet[pos+1])
pos += 2
p.Height[i] = uint16(packet[pos])<<8 | uint16(packet[pos+1])
Expand All @@ -356,17 +372,30 @@ func (p *VP9Packet) parseSSData(packet []byte, pos int) (int, error) {
}

if p.G {
if len(packet) <= pos {
return pos, errShortPacket
}

p.NG = packet[pos]
pos++
}

for i := 0; i < int(p.NG); i++ {
if len(packet) <= pos {
return pos, errShortPacket
}

p.PGTID = append(p.PGTID, packet[pos]>>5)
p.PGU = append(p.PGU, packet[pos]&0x10 != 0)
R := (packet[pos] >> 2) & 0x3
pos++

p.PGPDiff = append(p.PGPDiff, []uint8{})

if len(packet) <= (pos + int(R) - 1) {
return pos, errShortPacket
}

for j := 0; j < int(R); j++ {
p.PGPDiff[i] = append(p.PGPDiff[i], packet[pos])
pos++
Expand Down
16 changes: 16 additions & 0 deletions codecs/vp9_packet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,22 @@ func TestVP9Packet_Unmarshal(t *testing.T) {
Payload: []byte{},
},
},
"ScalabilityMissingWidth": {
b: []byte("200"),
err: errShortPacket,
},
"ScalabilityMissingNG": {
b: []byte("b00200000000"),
err: errShortPacket,
},
"ScalabilityMissingTemporalLayerIDs": {
b: []byte("20B0"),
err: errShortPacket,
},
"ScalabilityMissingReferenceIndices": {
b: []byte("20B007"),
err: errShortPacket,
},
}
for name, c := range cases {
c := c
Expand Down

0 comments on commit 9f0d145

Please sign in to comment.