prevent decoders from returning empty NALUs (bluenviron/mediamtx#4346) (#726)

This commit is contained in:
Alessandro Ros
2025-03-22 22:45:54 +01:00
committed by GitHub
parent b6d6f6bf37
commit fa94080e84
44 changed files with 191 additions and 112 deletions

View File

@@ -60,6 +60,12 @@ func (d *Decoder) decodeOBUs(pkt *rtp.Packet) ([][]byte, error) {
return nil, fmt.Errorf("invalid header: %w", err)
}
for _, obu := range av1header.OBUElements {
if len(obu) == 0 {
return nil, fmt.Errorf("invalid OBU size")
}
}
if av1header.Z {
if d.fragmentsSize == 0 {
if !d.firstPacketReceived {

View File

@@ -295,32 +295,39 @@ func TestDecodeErrorMissingPacket(t *testing.T) {
}
func FuzzDecoder(f *testing.F) {
f.Fuzz(func(_ *testing.T, a []byte, am bool, b []byte, bm bool) {
f.Fuzz(func(t *testing.T, a []byte, am bool, b []byte, bm bool) {
d := &Decoder{}
d.Init() //nolint:errcheck
err := d.Init()
require.NoError(t, err)
d.Decode(&rtp.Packet{ //nolint:errcheck
tu, err := d.Decode(&rtp.Packet{
Header: rtp.Header{
Version: 2,
Marker: am,
PayloadType: 96,
SequenceNumber: 17645,
Timestamp: 2289527317,
SSRC: 0x9dbb7812,
},
Payload: a,
})
d.Decode(&rtp.Packet{ //nolint:errcheck
if errors.Is(err, ErrMorePacketsNeeded) {
tu, err = d.Decode(&rtp.Packet{
Header: rtp.Header{
Version: 2,
Marker: bm,
PayloadType: 96,
SequenceNumber: 17646,
Timestamp: 2289527317,
SSRC: 0x9dbb7812,
},
Payload: b,
})
}
if err == nil {
if len(tu) == 0 {
t.Errorf("should not happen")
}
for _, nalu := range tu {
if len(nalu) == 0 {
t.Errorf("should not happen")
}
}
}
})
}

View File

@@ -2,4 +2,4 @@ go test fuzz v1
[]byte("0\x00")
bool(true)
[]byte("0")
bool(false)
bool(true)

View File

@@ -0,0 +1,5 @@
go test fuzz v1
[]byte("0")
bool(false)
[]byte("0")
bool(false)

View File

@@ -1,5 +1,5 @@
go test fuzz v1
[]byte("\x190")
[]byte("\x180")
bool(false)
[]byte("\xd00")
bool(false)

View File

@@ -1,5 +1,5 @@
go test fuzz v1
[]byte("\xd00")
bool(false)
[]byte("")
[]byte("0")
bool(false)

View File

@@ -157,11 +157,15 @@ func (d *Decoder) decodeNALUs(pkt *rtp.Packet) ([][]byte, error) {
size := uint16(payload[0])<<8 | uint16(payload[1])
payload = payload[2:]
if size == 0 {
// discard padding
if size == 0 && isAllZero(payload) {
if isAllZero(payload) {
break
}
return nil, fmt.Errorf("invalid STAP-A packet (invalid size)")
}
if int(size) > len(payload) {
return nil, fmt.Errorf("invalid STAP-A packet (invalid size)")
}

View File

@@ -275,32 +275,39 @@ func TestDecodeErrorMissingPacket(t *testing.T) {
}
func FuzzDecoder(f *testing.F) {
f.Fuzz(func(_ *testing.T, a []byte, b []byte) {
f.Fuzz(func(t *testing.T, a []byte, am bool, b []byte, bm bool) {
d := &Decoder{}
d.Init() //nolint:errcheck
err := d.Init()
require.NoError(t, err)
d.Decode(&rtp.Packet{ //nolint:errcheck
au, err := d.Decode(&rtp.Packet{
Header: rtp.Header{
Version: 2,
Marker: false,
PayloadType: 96,
Marker: am,
SequenceNumber: 17645,
Timestamp: 2289527317,
SSRC: 0x9dbb7812,
},
Payload: a,
})
d.Decode(&rtp.Packet{ //nolint:errcheck
if errors.Is(err, ErrMorePacketsNeeded) {
au, err = d.Decode(&rtp.Packet{
Header: rtp.Header{
Version: 2,
Marker: false,
PayloadType: 96,
SequenceNumber: 17645,
Timestamp: 2289527317,
SSRC: 0x9dbb7812,
Marker: bm,
SequenceNumber: 17646,
},
Payload: b,
})
}
if err == nil {
if len(au) == 0 {
t.Errorf("should not happen")
}
for _, nalu := range au {
if len(nalu) == 0 {
t.Errorf("should not happen")
}
}
}
})
}

View File

@@ -0,0 +1,5 @@
go test fuzz v1
[]byte("8")
bool(false)
[]byte("0")
bool(true)

View File

@@ -0,0 +1,5 @@
go test fuzz v1
[]byte("0")
bool(false)
[]byte("\x00\x00\x00\x01")
bool(false)

View File

@@ -1,3 +1,5 @@
go test fuzz v1
[]byte("800")
bool(false)
[]byte("0")
bool(true)

View File

@@ -1,3 +0,0 @@
go test fuzz v1
[]byte("0")
[]byte("8\x00\x000")

View File

@@ -1,5 +1,5 @@
go test fuzz v1
[]byte("")
bool(false)
[]byte("")
bool(false)
[]byte("0")
bool(true)

View File

@@ -0,0 +1,5 @@
go test fuzz v1
[]byte("0")
bool(false)
[]byte("8\x00\x00\x00\x010")
bool(true)

View File

@@ -1,3 +0,0 @@
go test fuzz v1
[]byte("8")
[]byte("")

View File

@@ -0,0 +1,5 @@
go test fuzz v1
[]byte("\xdc")
bool(false)
[]byte("0")
bool(false)

View File

@@ -1,3 +0,0 @@
go test fuzz v1
[]byte("0")
[]byte("")

View File

@@ -1,3 +0,0 @@
go test fuzz v1
[]byte("0")
[]byte("80")

View File

@@ -0,0 +1,5 @@
go test fuzz v1
[]byte("0")
bool(false)
[]byte("0")
bool(true)

View File

@@ -0,0 +1,5 @@
go test fuzz v1
[]byte("\xdc0")
bool(false)
[]byte("0")
bool(false)

View File

@@ -0,0 +1,5 @@
go test fuzz v1
[]byte("8\x00\x00")
bool(false)
[]byte("0")
bool(true)

View File

@@ -1,3 +0,0 @@
go test fuzz v1
[]byte("0")
[]byte("<")

View File

@@ -1,3 +0,0 @@
go test fuzz v1
[]byte("0")
[]byte("\\0")

View File

@@ -0,0 +1,5 @@
go test fuzz v1
[]byte("0")
bool(false)
[]byte("9000")
bool(false)

View File

@@ -1,3 +0,0 @@
go test fuzz v1
[]byte("0")
[]byte("9")

View File

@@ -0,0 +1,5 @@
go test fuzz v1
[]byte("0")
bool(false)
[]byte("|0")
bool(true)

View File

@@ -81,7 +81,7 @@ func (d *Decoder) decodeNALUs(pkt *rtp.Packet) ([][]byte, error) {
size := uint16(payload[0])<<8 | uint16(payload[1])
payload = payload[2:]
if int(size) > len(payload) {
if size == 0 || int(size) > len(payload) {
return nil, fmt.Errorf("invalid aggregation unit (invalid size)")
}
@@ -93,10 +93,6 @@ func (d *Decoder) decodeNALUs(pkt *rtp.Packet) ([][]byte, error) {
}
}
if nalus == nil {
return nil, fmt.Errorf("aggregation unit doesn't contain any NALU")
}
d.firstPacketReceived = true
case h265.NALUType_FragmentationUnit:

View File

@@ -92,32 +92,39 @@ func TestDecodeErrorMissingPacket(t *testing.T) {
}
func FuzzDecoder(f *testing.F) {
f.Fuzz(func(_ *testing.T, a []byte, b []byte) {
f.Fuzz(func(t *testing.T, a []byte, am bool, b []byte, bm bool) {
d := &Decoder{}
d.Init() //nolint:errcheck
err := d.Init()
require.NoError(t, err)
d.Decode(&rtp.Packet{ //nolint:errcheck
au, err := d.Decode(&rtp.Packet{
Header: rtp.Header{
Version: 2,
Marker: false,
PayloadType: 96,
Marker: am,
SequenceNumber: 17645,
Timestamp: 2289527317,
SSRC: 0x9dbb7812,
},
Payload: a,
})
d.Decode(&rtp.Packet{ //nolint:errcheck
if errors.Is(err, ErrMorePacketsNeeded) {
au, err = d.Decode(&rtp.Packet{
Header: rtp.Header{
Version: 2,
Marker: false,
PayloadType: 96,
SequenceNumber: 17645,
Timestamp: 2289527317,
SSRC: 0x9dbb7812,
Marker: bm,
SequenceNumber: 17646,
},
Payload: b,
})
}
if err == nil {
if len(au) == 0 {
t.Errorf("should not happen")
}
for _, nalu := range au {
if len(nalu) == 0 {
t.Errorf("should not happen")
}
}
}
})
}

View File

@@ -1,3 +1,5 @@
go test fuzz v1
[]byte("0")
[]byte("b0")
bool(false)
[]byte("0")
bool(false)

View File

@@ -0,0 +1,5 @@
go test fuzz v1
[]byte("a0")
bool(false)
[]byte("0")
bool(true)

View File

@@ -0,0 +1,5 @@
go test fuzz v1
[]byte("d0")
bool(false)
[]byte("0")
bool(true)

View File

@@ -1,3 +0,0 @@
go test fuzz v1
[]byte("00")
[]byte("b00")

View File

@@ -1,3 +0,0 @@
go test fuzz v1
[]byte("0")
[]byte("a00")

View File

@@ -0,0 +1,5 @@
go test fuzz v1
[]byte("00")
bool(false)
[]byte("b0\xc1")
bool(true)

View File

@@ -1,3 +0,0 @@
go test fuzz v1
[]byte("0")
[]byte("\xe50")

View File

@@ -0,0 +1,5 @@
go test fuzz v1
[]byte("b00")
bool(false)
[]byte("0")
bool(false)

View File

@@ -1,3 +0,0 @@
go test fuzz v1
[]byte("0")
[]byte("")

View File

@@ -1,3 +0,0 @@
go test fuzz v1
[]byte("a0")
[]byte("")

View File

@@ -0,0 +1,5 @@
go test fuzz v1
[]byte("0")
bool(false)
[]byte("0")
bool(true)

View File

@@ -1,3 +0,0 @@
go test fuzz v1
[]byte("b0\xd2")
[]byte("0")

View File

@@ -0,0 +1,5 @@
go test fuzz v1
[]byte("00")
bool(false)
[]byte("00")
bool(true)

View File

@@ -0,0 +1,5 @@
go test fuzz v1
[]byte("a0\x00\t000000000")
bool(false)
[]byte("b00")
bool(true)

View File

@@ -0,0 +1,5 @@
go test fuzz v1
[]byte("00")
bool(false)
[]byte("a0\x00\x00")
bool(true)

View File

@@ -1,3 +0,0 @@
go test fuzz v1
[]byte("a000")
[]byte("0")