* 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:
Aleksandr Razumov 2019-05-24 19:34:48 +03:00 коммит произвёл Sean DuBois
Родитель bb439befbe
Коммит fcc2cfd098
17 изменённых файлов: 138 добавлений и 5 удалений

21
.editorconfig Normal file
Просмотреть файл

@ -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(')

2
.gitignore поставляемый Normal file
Просмотреть файл

@ -0,0 +1,2 @@
vendor
*-fuzz.zip

6
Makefile Normal file
Просмотреть файл

@ -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)

Просмотреть файл

@ -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))
} }

36
fuzz.go Normal file
Просмотреть файл

@ -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]