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
|
||||
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(')
|
||||
|
||||
|
||||
|
|
|
@ -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*
|
||||
* [Hugo Arregui](https://github.com/hugoArregui)
|
||||
* [Lander Noterman](https://github.com/LanderN)
|
||||
* [Aleksandr Razumov](https://github.com/ernado) - *Fuzzing*
|
||||
|
||||
### License
|
||||
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
|
||||
rtrn := []cipherSuite{}
|
||||
for i := 0; i < cipherSuitesCount; i++ {
|
||||
if len(buf) < (i*2 + 4) {
|
||||
return nil, errBufferTooSmall
|
||||
}
|
||||
id := CipherSuiteID(binary.BigEndian.Uint16(buf[(i*2)+2:]))
|
||||
if c := cipherSuiteForID(id); c != nil {
|
||||
rtrn = append(rtrn, c)
|
||||
|
|
|
@ -25,6 +25,9 @@ func decodeCompressionMethods(buf []byte) ([]*compressionMethod, error) {
|
|||
compressionMethodsCount := int(buf[0])
|
||||
c := []*compressionMethod{}
|
||||
for i := 0; i < compressionMethodsCount; i++ {
|
||||
if len(buf) <= i+1 {
|
||||
return nil, errBufferTooSmall
|
||||
}
|
||||
id := compressionMethodID(buf[i+1])
|
||||
if compressionMethod, ok := compressionMethods[id]; ok {
|
||||
c = append(c, compressionMethod)
|
||||
|
|
10
extension.go
10
extension.go
|
@ -22,6 +22,9 @@ type extension interface {
|
|||
}
|
||||
|
||||
func decodeExtensions(buf []byte) ([]extension, error) {
|
||||
if len(buf) < 2 {
|
||||
return nil, errBufferTooSmall
|
||||
}
|
||||
declaredLen := binary.BigEndian.Uint16(buf)
|
||||
if len(buf)-2 != int(declaredLen) {
|
||||
return nil, errLengthMismatch
|
||||
|
@ -38,6 +41,9 @@ func decodeExtensions(buf []byte) ([]extension, error) {
|
|||
}
|
||||
|
||||
for offset := 2; offset < len(buf); {
|
||||
if len(buf) < (offset + 2) {
|
||||
return nil, errBufferTooSmall
|
||||
}
|
||||
var err error
|
||||
switch extensionValue(binary.BigEndian.Uint16(buf[offset:])) {
|
||||
case extensionSupportedEllipticCurvesValue:
|
||||
|
@ -49,7 +55,9 @@ func decodeExtensions(buf []byte) ([]extension, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(buf) < (offset + 4) {
|
||||
return nil, errBufferTooSmall
|
||||
}
|
||||
extensionLength := binary.BigEndian.Uint16(buf[offset+2:])
|
||||
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
|
||||
|
||||
if len(data) < offset+2 {
|
||||
return errBufferTooSmall
|
||||
}
|
||||
signatureHashAlgorithmsLength := int(binary.BigEndian.Uint16(data[offset:]))
|
||||
offset += 2
|
||||
|
||||
|
@ -71,6 +73,9 @@ func (h *handshakeMessageCertificateRequest) Unmarshal(data []byte) error {
|
|||
}
|
||||
|
||||
for i := 0; i < signatureHashAlgorithmsLength; i += 2 {
|
||||
if len(data) < (offset + i + 2) {
|
||||
return errBufferTooSmall
|
||||
}
|
||||
hash := HashAlgorithm(data[offset+i])
|
||||
signature := signatureAlgorithm(data[offset+i+1])
|
||||
|
||||
|
|
|
@ -58,6 +58,10 @@ func (h *handshakeMessageClientHello) Marshal() ([]byte, error) {
|
|||
}
|
||||
|
||||
func (h *handshakeMessageClientHello) Unmarshal(data []byte) error {
|
||||
if len(data) < 2+handshakeRandomLength {
|
||||
return errBufferTooSmall
|
||||
}
|
||||
|
||||
h.version.major = data[0]
|
||||
h.version.minor = data[1]
|
||||
|
||||
|
@ -70,23 +74,38 @@ func (h *handshakeMessageClientHello) Unmarshal(data []byte) error {
|
|||
currOffset += int(data[currOffset]) + 1 // SessionID
|
||||
|
||||
currOffset++
|
||||
if len(data) < currOffset {
|
||||
return errBufferTooSmall
|
||||
}
|
||||
h.cookie = append([]byte{}, data[currOffset:currOffset+int(data[currOffset-1])]...)
|
||||
currOffset += len(h.cookie)
|
||||
|
||||
// Cipher Suites
|
||||
if len(data) < currOffset {
|
||||
return errBufferTooSmall
|
||||
}
|
||||
cipherSuites, err := decodeCipherSuites(data[currOffset:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
h.cipherSuites = cipherSuites
|
||||
if len(data) < currOffset+2 {
|
||||
return errBufferTooSmall
|
||||
}
|
||||
currOffset += int(binary.BigEndian.Uint16(data[currOffset:])) + 2
|
||||
|
||||
// Compression Methods
|
||||
if len(data) < currOffset {
|
||||
return errBufferTooSmall
|
||||
}
|
||||
compressionMethods, err := decodeCompressionMethods(data[currOffset:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
h.compressionMethods = compressionMethods
|
||||
if len(data) < currOffset {
|
||||
return errBufferTooSmall
|
||||
}
|
||||
currOffset += int(data[currOffset]) + 1
|
||||
|
||||
// Extensions
|
||||
|
|
|
@ -13,6 +13,9 @@ func (h *handshakeMessageClientKeyExchange) Marshal() ([]byte, error) {
|
|||
}
|
||||
|
||||
func (h *handshakeMessageClientKeyExchange) Unmarshal(data []byte) error {
|
||||
if len(data) < 1 {
|
||||
return errBufferTooSmall
|
||||
}
|
||||
publicKeyLength := int(data[0])
|
||||
if len(data) <= publicKeyLength {
|
||||
return errBufferTooSmall
|
||||
|
|
|
@ -41,9 +41,15 @@ func (h *handshakeMessageHelloVerifyRequest) Marshal() ([]byte, error) {
|
|||
}
|
||||
|
||||
func (h *handshakeMessageHelloVerifyRequest) Unmarshal(data []byte) error {
|
||||
if len(data) < 3 {
|
||||
return errBufferTooSmall
|
||||
}
|
||||
h.version.major = data[0]
|
||||
h.version.minor = data[1]
|
||||
cookieLength := data[2]
|
||||
if len(data) < (int(cookieLength) + 3) {
|
||||
return errBufferTooSmall
|
||||
}
|
||||
h.cookie = make([]byte, 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 {
|
||||
if len(data) < 2+handshakeRandomLength {
|
||||
return errBufferTooSmall
|
||||
}
|
||||
|
||||
h.version.major = data[0]
|
||||
h.version.minor = data[1]
|
||||
|
||||
|
@ -68,14 +72,18 @@ func (h *handshakeMessageServerHello) Unmarshal(data []byte) error {
|
|||
|
||||
currOffset := handshakeMessageServerHelloVariableWidthStart
|
||||
currOffset += int(data[currOffset]) + 1 // SessionID
|
||||
|
||||
if len(data) < (currOffset + 2) {
|
||||
return errBufferTooSmall
|
||||
}
|
||||
if c := cipherSuiteForID(CipherSuiteID(binary.BigEndian.Uint16(data[currOffset:]))); c != nil {
|
||||
h.cipherSuite = c
|
||||
currOffset += 2
|
||||
} else {
|
||||
return errInvalidCipherSuite
|
||||
}
|
||||
|
||||
if len(data) < currOffset {
|
||||
return errBufferTooSmall
|
||||
}
|
||||
if compressionMethod, ok := compressionMethods[compressionMethodID(data[currOffset])]; ok {
|
||||
h.compressionMethod = compressionMethod
|
||||
currOffset++
|
||||
|
|
|
@ -34,6 +34,9 @@ func (h *handshakeMessageServerKeyExchange) Marshal() ([]byte, error) {
|
|||
}
|
||||
|
||||
func (h *handshakeMessageServerKeyExchange) Unmarshal(data []byte) error {
|
||||
if len(data) < 1 {
|
||||
return errBufferTooSmall
|
||||
}
|
||||
if _, ok := ellipticCurveTypes[ellipticCurveType(data[0])]; ok {
|
||||
h.ellipticCurveType = ellipticCurveType(data[0])
|
||||
} else {
|
||||
|
@ -44,6 +47,9 @@ func (h *handshakeMessageServerKeyExchange) Unmarshal(data []byte) error {
|
|||
if _, ok := namedCurves[h.namedCurve]; !ok {
|
||||
return errInvalidNamedCurve
|
||||
}
|
||||
if len(data) < 4 {
|
||||
return errBufferTooSmall
|
||||
}
|
||||
|
||||
publicKeyLength := int(data[3])
|
||||
offset := 4 + publicKeyLength
|
||||
|
|
|
@ -43,6 +43,9 @@ func (r *recordLayer) Marshal() ([]byte, error) {
|
|||
}
|
||||
|
||||
func (r *recordLayer) Unmarshal(data []byte) error {
|
||||
if len(data) < recordLayerHeaderSize {
|
||||
return errBufferTooSmall
|
||||
}
|
||||
if err := r.recordLayerHeader.Unmarshal(data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -42,6 +42,9 @@ func (r *recordLayerHeader) Marshal() ([]byte, error) {
|
|||
}
|
||||
|
||||
func (r *recordLayerHeader) Unmarshal(data []byte) error {
|
||||
if len(data) < 12 {
|
||||
return errBufferTooSmall
|
||||
}
|
||||
r.contentType = contentType(data[0])
|
||||
r.protocolVersion.major = data[1]
|
||||
r.protocolVersion.minor = data[2]
|
||||
|
|
Загрузка…
Ссылка в новой задаче