Fuzz: initial commit
* Add fuzz.go and FuzzRecordLayer func * Add Makefile * Update contributors * Update EXCLUDE_DIRECTORIES with "fuzz" * Fix found index out of range errors
This commit is contained in:
Родитель
bb439befbe
Коммит
fcc2cfd098
|
@ -0,0 +1,21 @@
|
||||||
|
# http://editorconfig.org/
|
||||||
|
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
end_of_line = lf
|
||||||
|
|
||||||
|
[*.go]
|
||||||
|
indent_style = tab
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
[{*.yml,*.yaml}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
# Makefiles always use tabs for indentation
|
||||||
|
[Makefile]
|
||||||
|
indent_style = tab
|
|
@ -3,7 +3,7 @@ set -e
|
||||||
|
|
||||||
# Disallow usages of functions that cause the program to exit in the library code
|
# Disallow usages of functions that cause the program to exit in the library code
|
||||||
SCRIPT_PATH=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P )
|
SCRIPT_PATH=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P )
|
||||||
EXCLUDE_DIRECTORIES="--exclude-dir=examples --exclude-dir=.git --exclude-dir=.github --exclude-dir=ccm "
|
EXCLUDE_DIRECTORIES="--exclude-dir=examples --exclude-dir=.git --exclude fuzz\.go --exclude-dir=vendor --exclude-dir=.github --exclude-dir=ccm "
|
||||||
DISALLOWED_FUNCTIONS=('os.Exit(' 'panic(' 'Fatal(' 'Fatalf(' 'Fatalln(' 'fmt.Println(' 'fmt.Printf(' 'log.Print(' 'log.Println(' 'log.Printf(')
|
DISALLOWED_FUNCTIONS=('os.Exit(' 'panic(' 'Fatal(' 'Fatalf(' 'Fatalln(' 'fmt.Println(' 'fmt.Printf(' 'log.Print(' 'log.Println(' 'log.Printf(')
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
vendor
|
||||||
|
*-fuzz.zip
|
|
@ -0,0 +1,6 @@
|
||||||
|
fuzz-build-record-layer: fuzz-prepare
|
||||||
|
go-fuzz-build -tags gofuzz -func FuzzRecordLayer
|
||||||
|
fuzz-run-record-layer:
|
||||||
|
go-fuzz -bin dtls-fuzz.zip -workdir fuzz
|
||||||
|
fuzz-prepare:
|
||||||
|
@GO111MODULE=on go mod vendor
|
|
@ -79,6 +79,7 @@ Check out the **[contributing wiki](https://github.com/pion/webrtc/wiki/Contribu
|
||||||
* [Jin Lei](https://github.com/jinleileiking) - *Logging*
|
* [Jin Lei](https://github.com/jinleileiking) - *Logging*
|
||||||
* [Hugo Arregui](https://github.com/hugoArregui)
|
* [Hugo Arregui](https://github.com/hugoArregui)
|
||||||
* [Lander Noterman](https://github.com/LanderN)
|
* [Lander Noterman](https://github.com/LanderN)
|
||||||
|
* [Aleksandr Razumov](https://github.com/ernado) - *Fuzzing*
|
||||||
|
|
||||||
### License
|
### License
|
||||||
MIT License - see [LICENSE](LICENSE) for full text
|
MIT License - see [LICENSE](LICENSE) for full text
|
||||||
|
|
|
@ -69,6 +69,9 @@ func decodeCipherSuites(buf []byte) ([]cipherSuite, error) {
|
||||||
cipherSuitesCount := int(binary.BigEndian.Uint16(buf[0:])) / 2
|
cipherSuitesCount := int(binary.BigEndian.Uint16(buf[0:])) / 2
|
||||||
rtrn := []cipherSuite{}
|
rtrn := []cipherSuite{}
|
||||||
for i := 0; i < cipherSuitesCount; i++ {
|
for i := 0; i < cipherSuitesCount; i++ {
|
||||||
|
if len(buf) < (i*2 + 4) {
|
||||||
|
return nil, errBufferTooSmall
|
||||||
|
}
|
||||||
id := CipherSuiteID(binary.BigEndian.Uint16(buf[(i*2)+2:]))
|
id := CipherSuiteID(binary.BigEndian.Uint16(buf[(i*2)+2:]))
|
||||||
if c := cipherSuiteForID(id); c != nil {
|
if c := cipherSuiteForID(id); c != nil {
|
||||||
rtrn = append(rtrn, c)
|
rtrn = append(rtrn, c)
|
||||||
|
|
|
@ -25,6 +25,9 @@ func decodeCompressionMethods(buf []byte) ([]*compressionMethod, error) {
|
||||||
compressionMethodsCount := int(buf[0])
|
compressionMethodsCount := int(buf[0])
|
||||||
c := []*compressionMethod{}
|
c := []*compressionMethod{}
|
||||||
for i := 0; i < compressionMethodsCount; i++ {
|
for i := 0; i < compressionMethodsCount; i++ {
|
||||||
|
if len(buf) <= i+1 {
|
||||||
|
return nil, errBufferTooSmall
|
||||||
|
}
|
||||||
id := compressionMethodID(buf[i+1])
|
id := compressionMethodID(buf[i+1])
|
||||||
if compressionMethod, ok := compressionMethods[id]; ok {
|
if compressionMethod, ok := compressionMethods[id]; ok {
|
||||||
c = append(c, compressionMethod)
|
c = append(c, compressionMethod)
|
||||||
|
|
10
extension.go
10
extension.go
|
@ -22,6 +22,9 @@ type extension interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
func decodeExtensions(buf []byte) ([]extension, error) {
|
func decodeExtensions(buf []byte) ([]extension, error) {
|
||||||
|
if len(buf) < 2 {
|
||||||
|
return nil, errBufferTooSmall
|
||||||
|
}
|
||||||
declaredLen := binary.BigEndian.Uint16(buf)
|
declaredLen := binary.BigEndian.Uint16(buf)
|
||||||
if len(buf)-2 != int(declaredLen) {
|
if len(buf)-2 != int(declaredLen) {
|
||||||
return nil, errLengthMismatch
|
return nil, errLengthMismatch
|
||||||
|
@ -38,6 +41,9 @@ func decodeExtensions(buf []byte) ([]extension, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for offset := 2; offset < len(buf); {
|
for offset := 2; offset < len(buf); {
|
||||||
|
if len(buf) < (offset + 2) {
|
||||||
|
return nil, errBufferTooSmall
|
||||||
|
}
|
||||||
var err error
|
var err error
|
||||||
switch extensionValue(binary.BigEndian.Uint16(buf[offset:])) {
|
switch extensionValue(binary.BigEndian.Uint16(buf[offset:])) {
|
||||||
case extensionSupportedEllipticCurvesValue:
|
case extensionSupportedEllipticCurvesValue:
|
||||||
|
@ -49,7 +55,9 @@ func decodeExtensions(buf []byte) ([]extension, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if len(buf) < (offset + 4) {
|
||||||
|
return nil, errBufferTooSmall
|
||||||
|
}
|
||||||
extensionLength := binary.BigEndian.Uint16(buf[offset+2:])
|
extensionLength := binary.BigEndian.Uint16(buf[offset+2:])
|
||||||
offset += (4 + int(extensionLength))
|
offset += (4 + int(extensionLength))
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
// +build gofuzz
|
||||||
|
|
||||||
|
package dtls
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func partialHeaderMismatch(a, b recordLayerHeader) bool {
|
||||||
|
// Ignoring content length for now.
|
||||||
|
a.contentLen = b.contentLen
|
||||||
|
return a != b
|
||||||
|
}
|
||||||
|
|
||||||
|
func FuzzRecordLayer(data []byte) int {
|
||||||
|
var r recordLayer
|
||||||
|
if err := r.Unmarshal(data); err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
buf, err := r.Marshal()
|
||||||
|
if err != nil {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
if len(buf) == 0 {
|
||||||
|
panic("zero buff")
|
||||||
|
}
|
||||||
|
var nr recordLayer
|
||||||
|
if err = nr.Unmarshal(data); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if partialHeaderMismatch(nr.recordLayerHeader, r.recordLayerHeader) {
|
||||||
|
panic(fmt.Sprintf("header mismatch: %+v != %+v",
|
||||||
|
nr.recordLayerHeader, r.recordLayerHeader,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
|
@ -62,7 +62,9 @@ func (h *handshakeMessageCertificateRequest) Unmarshal(data []byte) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
offset += certificateTypesLength
|
offset += certificateTypesLength
|
||||||
|
if len(data) < offset+2 {
|
||||||
|
return errBufferTooSmall
|
||||||
|
}
|
||||||
signatureHashAlgorithmsLength := int(binary.BigEndian.Uint16(data[offset:]))
|
signatureHashAlgorithmsLength := int(binary.BigEndian.Uint16(data[offset:]))
|
||||||
offset += 2
|
offset += 2
|
||||||
|
|
||||||
|
@ -71,6 +73,9 @@ func (h *handshakeMessageCertificateRequest) Unmarshal(data []byte) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < signatureHashAlgorithmsLength; i += 2 {
|
for i := 0; i < signatureHashAlgorithmsLength; i += 2 {
|
||||||
|
if len(data) < (offset + i + 2) {
|
||||||
|
return errBufferTooSmall
|
||||||
|
}
|
||||||
hash := HashAlgorithm(data[offset+i])
|
hash := HashAlgorithm(data[offset+i])
|
||||||
signature := signatureAlgorithm(data[offset+i+1])
|
signature := signatureAlgorithm(data[offset+i+1])
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,10 @@ func (h *handshakeMessageClientHello) Marshal() ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *handshakeMessageClientHello) Unmarshal(data []byte) error {
|
func (h *handshakeMessageClientHello) Unmarshal(data []byte) error {
|
||||||
|
if len(data) < 2+handshakeRandomLength {
|
||||||
|
return errBufferTooSmall
|
||||||
|
}
|
||||||
|
|
||||||
h.version.major = data[0]
|
h.version.major = data[0]
|
||||||
h.version.minor = data[1]
|
h.version.minor = data[1]
|
||||||
|
|
||||||
|
@ -70,23 +74,38 @@ func (h *handshakeMessageClientHello) Unmarshal(data []byte) error {
|
||||||
currOffset += int(data[currOffset]) + 1 // SessionID
|
currOffset += int(data[currOffset]) + 1 // SessionID
|
||||||
|
|
||||||
currOffset++
|
currOffset++
|
||||||
|
if len(data) < currOffset {
|
||||||
|
return errBufferTooSmall
|
||||||
|
}
|
||||||
h.cookie = append([]byte{}, data[currOffset:currOffset+int(data[currOffset-1])]...)
|
h.cookie = append([]byte{}, data[currOffset:currOffset+int(data[currOffset-1])]...)
|
||||||
currOffset += len(h.cookie)
|
currOffset += len(h.cookie)
|
||||||
|
|
||||||
// Cipher Suites
|
// Cipher Suites
|
||||||
|
if len(data) < currOffset {
|
||||||
|
return errBufferTooSmall
|
||||||
|
}
|
||||||
cipherSuites, err := decodeCipherSuites(data[currOffset:])
|
cipherSuites, err := decodeCipherSuites(data[currOffset:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
h.cipherSuites = cipherSuites
|
h.cipherSuites = cipherSuites
|
||||||
|
if len(data) < currOffset+2 {
|
||||||
|
return errBufferTooSmall
|
||||||
|
}
|
||||||
currOffset += int(binary.BigEndian.Uint16(data[currOffset:])) + 2
|
currOffset += int(binary.BigEndian.Uint16(data[currOffset:])) + 2
|
||||||
|
|
||||||
// Compression Methods
|
// Compression Methods
|
||||||
|
if len(data) < currOffset {
|
||||||
|
return errBufferTooSmall
|
||||||
|
}
|
||||||
compressionMethods, err := decodeCompressionMethods(data[currOffset:])
|
compressionMethods, err := decodeCompressionMethods(data[currOffset:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
h.compressionMethods = compressionMethods
|
h.compressionMethods = compressionMethods
|
||||||
|
if len(data) < currOffset {
|
||||||
|
return errBufferTooSmall
|
||||||
|
}
|
||||||
currOffset += int(data[currOffset]) + 1
|
currOffset += int(data[currOffset]) + 1
|
||||||
|
|
||||||
// Extensions
|
// Extensions
|
||||||
|
|
|
@ -13,6 +13,9 @@ func (h *handshakeMessageClientKeyExchange) Marshal() ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *handshakeMessageClientKeyExchange) Unmarshal(data []byte) error {
|
func (h *handshakeMessageClientKeyExchange) Unmarshal(data []byte) error {
|
||||||
|
if len(data) < 1 {
|
||||||
|
return errBufferTooSmall
|
||||||
|
}
|
||||||
publicKeyLength := int(data[0])
|
publicKeyLength := int(data[0])
|
||||||
if len(data) <= publicKeyLength {
|
if len(data) <= publicKeyLength {
|
||||||
return errBufferTooSmall
|
return errBufferTooSmall
|
||||||
|
|
|
@ -41,9 +41,15 @@ func (h *handshakeMessageHelloVerifyRequest) Marshal() ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *handshakeMessageHelloVerifyRequest) Unmarshal(data []byte) error {
|
func (h *handshakeMessageHelloVerifyRequest) Unmarshal(data []byte) error {
|
||||||
|
if len(data) < 3 {
|
||||||
|
return errBufferTooSmall
|
||||||
|
}
|
||||||
h.version.major = data[0]
|
h.version.major = data[0]
|
||||||
h.version.minor = data[1]
|
h.version.minor = data[1]
|
||||||
cookieLength := data[2]
|
cookieLength := data[2]
|
||||||
|
if len(data) < (int(cookieLength) + 3) {
|
||||||
|
return errBufferTooSmall
|
||||||
|
}
|
||||||
h.cookie = make([]byte, cookieLength)
|
h.cookie = make([]byte, cookieLength)
|
||||||
|
|
||||||
copy(h.cookie, data[3:3+cookieLength])
|
copy(h.cookie, data[3:3+cookieLength])
|
||||||
|
|
|
@ -59,6 +59,10 @@ func (h *handshakeMessageServerHello) Marshal() ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *handshakeMessageServerHello) Unmarshal(data []byte) error {
|
func (h *handshakeMessageServerHello) Unmarshal(data []byte) error {
|
||||||
|
if len(data) < 2+handshakeRandomLength {
|
||||||
|
return errBufferTooSmall
|
||||||
|
}
|
||||||
|
|
||||||
h.version.major = data[0]
|
h.version.major = data[0]
|
||||||
h.version.minor = data[1]
|
h.version.minor = data[1]
|
||||||
|
|
||||||
|
@ -68,14 +72,18 @@ func (h *handshakeMessageServerHello) Unmarshal(data []byte) error {
|
||||||
|
|
||||||
currOffset := handshakeMessageServerHelloVariableWidthStart
|
currOffset := handshakeMessageServerHelloVariableWidthStart
|
||||||
currOffset += int(data[currOffset]) + 1 // SessionID
|
currOffset += int(data[currOffset]) + 1 // SessionID
|
||||||
|
if len(data) < (currOffset + 2) {
|
||||||
|
return errBufferTooSmall
|
||||||
|
}
|
||||||
if c := cipherSuiteForID(CipherSuiteID(binary.BigEndian.Uint16(data[currOffset:]))); c != nil {
|
if c := cipherSuiteForID(CipherSuiteID(binary.BigEndian.Uint16(data[currOffset:]))); c != nil {
|
||||||
h.cipherSuite = c
|
h.cipherSuite = c
|
||||||
currOffset += 2
|
currOffset += 2
|
||||||
} else {
|
} else {
|
||||||
return errInvalidCipherSuite
|
return errInvalidCipherSuite
|
||||||
}
|
}
|
||||||
|
if len(data) < currOffset {
|
||||||
|
return errBufferTooSmall
|
||||||
|
}
|
||||||
if compressionMethod, ok := compressionMethods[compressionMethodID(data[currOffset])]; ok {
|
if compressionMethod, ok := compressionMethods[compressionMethodID(data[currOffset])]; ok {
|
||||||
h.compressionMethod = compressionMethod
|
h.compressionMethod = compressionMethod
|
||||||
currOffset++
|
currOffset++
|
||||||
|
|
|
@ -34,6 +34,9 @@ func (h *handshakeMessageServerKeyExchange) Marshal() ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *handshakeMessageServerKeyExchange) Unmarshal(data []byte) error {
|
func (h *handshakeMessageServerKeyExchange) Unmarshal(data []byte) error {
|
||||||
|
if len(data) < 1 {
|
||||||
|
return errBufferTooSmall
|
||||||
|
}
|
||||||
if _, ok := ellipticCurveTypes[ellipticCurveType(data[0])]; ok {
|
if _, ok := ellipticCurveTypes[ellipticCurveType(data[0])]; ok {
|
||||||
h.ellipticCurveType = ellipticCurveType(data[0])
|
h.ellipticCurveType = ellipticCurveType(data[0])
|
||||||
} else {
|
} else {
|
||||||
|
@ -44,6 +47,9 @@ func (h *handshakeMessageServerKeyExchange) Unmarshal(data []byte) error {
|
||||||
if _, ok := namedCurves[h.namedCurve]; !ok {
|
if _, ok := namedCurves[h.namedCurve]; !ok {
|
||||||
return errInvalidNamedCurve
|
return errInvalidNamedCurve
|
||||||
}
|
}
|
||||||
|
if len(data) < 4 {
|
||||||
|
return errBufferTooSmall
|
||||||
|
}
|
||||||
|
|
||||||
publicKeyLength := int(data[3])
|
publicKeyLength := int(data[3])
|
||||||
offset := 4 + publicKeyLength
|
offset := 4 + publicKeyLength
|
||||||
|
|
|
@ -43,6 +43,9 @@ func (r *recordLayer) Marshal() ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *recordLayer) Unmarshal(data []byte) error {
|
func (r *recordLayer) Unmarshal(data []byte) error {
|
||||||
|
if len(data) < recordLayerHeaderSize {
|
||||||
|
return errBufferTooSmall
|
||||||
|
}
|
||||||
if err := r.recordLayerHeader.Unmarshal(data); err != nil {
|
if err := r.recordLayerHeader.Unmarshal(data); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,9 @@ func (r *recordLayerHeader) Marshal() ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *recordLayerHeader) Unmarshal(data []byte) error {
|
func (r *recordLayerHeader) Unmarshal(data []byte) error {
|
||||||
|
if len(data) < 12 {
|
||||||
|
return errBufferTooSmall
|
||||||
|
}
|
||||||
r.contentType = contentType(data[0])
|
r.contentType = contentType(data[0])
|
||||||
r.protocolVersion.major = data[1]
|
r.protocolVersion.major = data[1]
|
||||||
r.protocolVersion.minor = data[2]
|
r.protocolVersion.minor = data[2]
|
||||||
|
|
Загрузка…
Ссылка в новой задаче