golang: add fuzzers (#8305)

Signed-off-by: AdamKorcz <adam@adalogics.com>

Signed-off-by: AdamKorcz <adam@adalogics.com>
This commit is contained in:
AdamKorcz 2022-08-20 19:35:10 +01:00 committed by GitHub
parent e09da5ef6a
commit 7c18e1e5d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 275 additions and 0 deletions

View File

@ -25,6 +25,9 @@ COPY build.sh text_fuzzer.go \
regexp_fuzzer.go \
language_fuzzer.go \
unicode_fuzzer.go \
x509_fuzzer.go \
ecdsa_fuzzer.go \
aes_fuzzer.go \
elf_fuzzer.go $SRC/
WORKDIR $SRC/golang

View File

@ -0,0 +1,94 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package aes
import (
"crypto/aes"
"runtime"
"strings"
)
func catchPanics() {
if r := recover(); r != nil {
var err string
switch r.(type) {
case string:
err = r.(string)
case runtime.Error:
err = r.(runtime.Error).Error()
case error:
err = r.(error).Error()
}
if strings.Contains(err, "not full block") {
return
} else if strings.Contains(err, "invalid buffer overlap") {
return
} else {
panic(err)
}
}
}
func FuzzAesCipherDecrypt(data []byte) int {
if len(data) < 5 {
return 0
}
keyIndex := int(data[0])
lenIn := int(data[1])
if lenIn < aes.BlockSize {
return 0
}
data = data[2:]
if (keyIndex + 5) > len(data) {
return 0
}
key := data[:keyIndex]
c, err := aes.NewCipher(key)
if err != nil {
return 0
}
dst := make([]byte, lenIn)
src := data[keyIndex+1:]
defer catchPanics()
c.Decrypt(dst, src)
return 1
}
func FuzzAesCipherEncrypt(data []byte) int {
if len(data) < 5 {
return 0
}
keyIndex := int(data[0])
lenIn := int(data[1])
data = data[2:]
if (keyIndex + 5) > len(data) {
return 0
}
key := data[:keyIndex]
c, err := aes.NewCipher(key)
if err != nil {
return 0
}
dst := make([]byte, lenIn)
src := data[keyIndex+1:]
defer catchPanics()
c.Encrypt(dst, src)
return 1
}

View File

@ -28,8 +28,24 @@ cd $SRC/golang
mkdir text && cp $SRC/text_fuzzer.go ./text/
cp $SRC/language_fuzzer.go ./text/
mkdir -p crypto/x509
cp $SRC/x509_fuzzer.go ./crypto/x509/
mkdir -p crypto/ecdsa
cp $SRC/ecdsa_fuzzer.go ./crypto/ecdsa/
mkdir -p crypto/aes
cp $SRC/aes_fuzzer.go ./crypto/aes/
go mod init "github.com/dvyukov/go-fuzz-corpus"
export FUZZ_ROOT="github.com/dvyukov/go-fuzz-corpus"
compile_go_fuzzer $FUZZ_ROOT/crypto/x509 FuzzParseCert fuzz_parse_cert
zip $OUT/fuzz_parse_cert_seed_corpus.zip $SRC/go/src/crypto/x509/testdata/*
compile_go_fuzzer $FUZZ_ROOT/crypto/x509 FuzzPemDecrypt fuzz_pem_decrypt
zip $OUT/fuzz_pem_decrypt_seed_corpus.zip $SRC/go/src/crypto/x509/testdata/*
compile_go_fuzzer $FUZZ_ROOT/crypto/aes FuzzAesCipherDecrypt fuzz_aes_cipher_decrypt
compile_go_fuzzer $FUZZ_ROOT/crypto/aes FuzzAesCipherEncrypt fuzz_aes_cipher_encrypt
compile_go_fuzzer $FUZZ_ROOT/crypto/ecdsa FuzzEcdsaSign FuzzEcdsaSign
compile_go_fuzzer $FUZZ_ROOT/text FuzzAcceptLanguage accept_language_fuzzer
compile_go_fuzzer $FUZZ_ROOT/text FuzzMultipleParsers fuzz_multiple_parsers
compile_go_fuzzer $FUZZ_ROOT/text FuzzCurrency currency_fuzzer
@ -63,6 +79,8 @@ go mod tidy
find . -name "*_test.go" ! -name 'fuzz_test.go' -type f -exec rm -f {} +
compile_go_fuzzer regexpPackage FuzzCompile fuzz_regexp_compile
compile_go_fuzzer regexpPackage FuzzCompilePOSIX fuzz_compile_posix
compile_go_fuzzer regexpPackage FuzzReplaceAll fuzz_replace_all
compile_go_fuzzer regexpPackage FuzzFindMatchApis fuzz_find_match_apis
cd $SRC/go/src/archive/tar
go mod init tarPackage

View File

@ -0,0 +1,44 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package ecdsa
import (
"bytes"
"crypto/ecdsa"
"crypto/elliptic"
)
func FuzzEcdsaSign(data []byte) int {
if len(data) < 5 {
return 0
}
c := []elliptic.Curve{
elliptic.P256(),
elliptic.P224(),
elliptic.P384(),
elliptic.P521(),
}
cIndex := int(data[0] % 4)
firstRandReaderLen := int(data[1])
data = data[2:]
if (firstRandReaderLen + 3) > len(data) {
return 0
}
randReader := bytes.NewReader(data[:firstRandReaderLen])
priv, _ := ecdsa.GenerateKey(c[cIndex], randReader)
_, _, _ = ecdsa.Sign(randReader, priv, data[firstRandReaderLen+1:])
return 1
}

View File

@ -24,3 +24,64 @@ func FuzzCompilePOSIX(data []byte) int {
_, _ = CompilePOSIX(string(data))
return 1
}
func FuzzReplaceAll(data []byte) int {
if len(data) < 5 {
return 0
}
chunk1Len := int(data[0])
chunk2Len := int(data[1])
if chunk2Len <= chunk1Len || chunk1Len < 3 || len(data) < (chunk2Len+2) {
return 0
}
chunk1 := data[2:chunk1Len]
chunk2 := data[chunk1Len+1 : chunk2Len]
chunk3 := data[chunk2Len+1:]
re, err := Compile(string(chunk1))
if err != nil {
return 0
}
_ = re.ReplaceAll(chunk2, chunk3)
return 1
}
func FuzzFindMatchApis(data []byte) int {
if len(data) < 5 {
return 0
}
callType := int(data[0])
chunk1Len := int(data[1])
data = data[2:]
if chunk1Len+2 >= len(data) {
return 0
}
reString := string(data[:chunk1Len])
apiPayload := data[chunk1Len+1:]
re, err := Compile(reString)
if err != nil {
return 0
}
switch callType % 6 {
case 0:
_ = re.FindIndex(apiPayload)
case 1:
_ = re.FindString(string(apiPayload))
case 2:
_ = re.FindStringIndex(string(apiPayload))
case 3:
_ = re.FindSubmatch(apiPayload)
case 4:
_ = re.MatchString(string(apiPayload))
case 5:
_ = re.Match(apiPayload)
}
return 1
}

View File

@ -0,0 +1,55 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package x509
import (
"crypto/x509"
"encoding/pem"
)
func FuzzParseCert(data []byte) int {
if len(data) < 2 {
return 1
}
plural := int(data[0])%2 == 0
data = data[1:]
if plural {
_, _ = x509.ParseCertificates(data)
} else {
_, _ = x509.ParseCertificate(data)
}
return 1
}
func FuzzPemDecrypt(data []byte) int {
if len(data) < 6 {
return 0
}
pemDataLen := int(data[0])
if (pemDataLen + 5) > len(data) {
return 0
}
data = data[1:]
pemData := data[:pemDataLen]
password := data[pemDataLen+1:]
block, _ := pem.Decode(pemData)
if block == nil {
return 0
}
_, _ = x509.DecryptPEMBlock(block, password)
return 1
}