h264: fix crash in Annex-B decoding, add fuzz tests

This commit is contained in:
aler9
2023-01-08 11:53:56 +01:00
parent 73c9840bbe
commit 8a1dd54d61
16 changed files with 86 additions and 112 deletions

View File

@@ -8,25 +8,38 @@ import (
func AnnexBUnmarshal(byts []byte) ([][]byte, error) {
bl := len(byts)
initZeroCount := 0
start := 0
outer:
for i := 0; i < bl; i++ {
switch byts[i] {
case 0:
for {
if start >= bl || start >= 4 {
return nil, fmt.Errorf("initial delimiter not found")
}
switch initZeroCount {
case 0, 1:
if byts[start] != 0 {
return nil, fmt.Errorf("initial delimiter not found")
}
initZeroCount++
case 1:
break outer
case 2, 3:
switch byts[start] {
case 1:
start++
break outer
default:
return nil, fmt.Errorf("unexpected byte: %d", byts[i])
case 0:
default:
return nil, fmt.Errorf("initial delimiter not found")
}
initZeroCount++
}
}
if initZeroCount != 2 && initZeroCount != 3 {
return nil, fmt.Errorf("initial delimiter not found")
start++
}
start := initZeroCount + 1
zeroCount := 0
n := 0
@@ -67,16 +80,15 @@ outer:
case 1:
if zeroCount == 2 || zeroCount == 3 {
if (delimStart - start) > MaxNALUSize {
return nil, fmt.Errorf("NALU size (%d) is too big (maximum is %d)", delimStart-start, MaxNALUSize)
l := delimStart - start
if l == 0 {
return nil, fmt.Errorf("invalid NALU")
}
if l > MaxNALUSize {
return nil, fmt.Errorf("NALU size (%d) is too big (maximum is %d)", l, MaxNALUSize)
}
nalu := byts[start:delimStart]
if len(nalu) == 0 {
return nil, fmt.Errorf("empty NALU")
}
ret[pos] = nalu
ret[pos] = byts[start:delimStart]
pos++
start = i + 1
}
@@ -87,15 +99,15 @@ outer:
}
}
if (bl - start) > MaxNALUSize {
return nil, fmt.Errorf("NALU size (%d) is too big (maximum is %d)", bl-start, MaxNALUSize)
l := bl - start
if l == 0 {
return nil, fmt.Errorf("invalid NALU")
}
if l > MaxNALUSize {
return nil, fmt.Errorf("NALU size (%d) is too big (maximum is %d)", l, MaxNALUSize)
}
nalu := byts[start:bl]
if len(nalu) == 0 {
return nil, fmt.Errorf("empty NALU")
}
ret[pos] = nalu
ret[pos] = byts[start:bl]
return ret, nil
}

View File

@@ -1,7 +1,6 @@
package h264
import (
"bytes"
"testing"
"github.com/stretchr/testify/require"
@@ -95,50 +94,6 @@ func TestAnnexBMarshal(t *testing.T) {
}
}
func TestAnnexBUnmarshalError(t *testing.T) {
for _, ca := range []struct {
name string
enc []byte
err string
}{
{
"empty",
[]byte{},
"initial delimiter not found",
},
{
"invalid initial delimiter 1",
[]byte{0xaa, 0xbb},
"unexpected byte: 170",
},
{
"invalid initial delimiter 2",
[]byte{0x00, 0x00, 0x00, 0x00, 0x01},
"initial delimiter not found",
},
{
"empty NALU 1",
[]byte{0x00, 0x00, 0x01, 0x00, 0x00, 0x01},
"empty NALU",
},
{
"empty NALU 2",
[]byte{0x00, 0x00, 0x01, 0xaa, 0x00, 0x00, 0x01},
"empty NALU",
},
{
"too many nalus",
bytes.Repeat([]byte{0x00, 0x00, 0x01, 0x0a}, 21),
"NALU count (21) exceeds maximum allowed (20)",
},
} {
t.Run(ca.name, func(t *testing.T) {
_, err := AnnexBUnmarshal(ca.enc)
require.EqualError(t, err, ca.err)
})
}
}
func BenchmarkAnnexBUnmarshal(b *testing.B) {
for i := 0; i < b.N; i++ {
AnnexBUnmarshal([]byte{
@@ -161,3 +116,9 @@ func BenchmarkAnnexBUnmarshal(b *testing.B) {
})
}
}
func FuzzAnnexBUnmarshal(f *testing.F) {
f.Fuzz(func(t *testing.T, b []byte) {
AnnexBUnmarshal(b)
})
}

View File

@@ -15,15 +15,15 @@ func AVCCUnmarshal(buf []byte) ([][]byte, error) {
return nil, fmt.Errorf("invalid length")
}
le := int(uint32(buf[pos])<<24 | uint32(buf[pos+1])<<16 | uint32(buf[pos+2])<<8 | uint32(buf[pos+3]))
l := int(uint32(buf[pos])<<24 | uint32(buf[pos+1])<<16 | uint32(buf[pos+2])<<8 | uint32(buf[pos+3]))
pos += 4
if (bl - pos) < le {
return nil, fmt.Errorf("invalid length")
if l == 0 {
return nil, fmt.Errorf("invalid NALU")
}
if (bl - pos) > MaxNALUSize {
return nil, fmt.Errorf("NALU size (%d) is too big (maximum is %d)", bl-pos, MaxNALUSize)
if l > MaxNALUSize {
return nil, fmt.Errorf("NALU size (%d) is too big (maximum is %d)", l, MaxNALUSize)
}
if (len(ret) + 1) > MaxNALUsPerGroup {
@@ -31,8 +31,12 @@ func AVCCUnmarshal(buf []byte) ([][]byte, error) {
len(ret)+1, MaxNALUsPerGroup)
}
ret = append(ret, buf[pos:pos+le])
pos += le
if (bl - pos) < l {
return nil, fmt.Errorf("invalid length")
}
ret = append(ret, buf[pos:pos+l])
pos += l
if (bl - pos) == 0 {
break

View File

@@ -1,7 +1,6 @@
package h264
import (
"bytes"
"testing"
"github.com/stretchr/testify/require"
@@ -60,36 +59,8 @@ func TestAVCCMarshal(t *testing.T) {
}
}
func TestAVCCUnmarshalError(t *testing.T) {
for _, ca := range []struct {
name string
enc []byte
err string
}{
{
"empty",
[]byte{},
"invalid length",
},
{
"invalid length",
[]byte{0x01},
"invalid length",
},
{
"invalid length",
[]byte{0x00, 0x00, 0x00, 0x03},
"invalid length",
},
{
"too many nalus",
bytes.Repeat([]byte{0x00, 0x00, 0x00, 0x01, 0x0a}, 21),
"NALU count (21) exceeds maximum allowed (20)",
},
} {
t.Run(ca.name, func(t *testing.T) {
_, err := AVCCUnmarshal(ca.enc)
require.EqualError(t, err, ca.err)
})
}
func FuzzAVCCUnmarshal(f *testing.F) {
f.Fuzz(func(t *testing.T, b []byte) {
AVCCUnmarshal(b)
})
}

View File

@@ -1,6 +1,6 @@
package h264
// EmulationPreventionRemove removes emlation prevention bytes from a NALU.
// EmulationPreventionRemove removes emulation prevention bytes from a NALU.
func EmulationPreventionRemove(nalu []byte) []byte {
// 0x00 0x00 0x03 0x00 -> 0x00 0x00 0x00
// 0x00 0x00 0x03 0x01 -> 0x00 0x00 0x01

View File

@@ -54,3 +54,9 @@ func TestEmulationPreventionRemove(t *testing.T) {
})
}
}
func FuzzEmulationPreventionRemove(f *testing.F) {
f.Fuzz(func(t *testing.T, b []byte) {
EmulationPreventionRemove(b)
})
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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