Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Add additional fuzzing probes #3473

Merged
merged 18 commits into from
Oct 9, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions checks/evaluation/fuzzing.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,18 @@ import (
"github.com/ossf/scorecard/v4/checker"
sce "github.com/ossf/scorecard/v4/errors"
"github.com/ossf/scorecard/v4/finding"
"github.com/ossf/scorecard/v4/probes/fuzzedWithCLibFuzzer"
"github.com/ossf/scorecard/v4/probes/fuzzedWithClusterFuzzLite"
"github.com/ossf/scorecard/v4/probes/fuzzedWithCppLibFuzzer"
"github.com/ossf/scorecard/v4/probes/fuzzedWithGoNative"
"github.com/ossf/scorecard/v4/probes/fuzzedWithJavaJazzerFuzzer"
"github.com/ossf/scorecard/v4/probes/fuzzedWithOSSFuzz"
"github.com/ossf/scorecard/v4/probes/fuzzedWithOneFuzz"
"github.com/ossf/scorecard/v4/probes/fuzzedWithPropertyBasedHaskell"
"github.com/ossf/scorecard/v4/probes/fuzzedWithPropertyBasedJavascript"
"github.com/ossf/scorecard/v4/probes/fuzzedWithPropertyBasedTypescript"
"github.com/ossf/scorecard/v4/probes/fuzzedWithPythonAtheris"
"github.com/ossf/scorecard/v4/probes/fuzzedWithRustCargofuzz"
)

// Fuzzing applies the score policy for the Fuzzing check.
Expand All @@ -35,6 +40,11 @@ func Fuzzing(name string,
expectedProbes := []string{
fuzzedWithClusterFuzzLite.Probe,
fuzzedWithGoNative.Probe,
fuzzedWithPythonAtheris.Probe,
DavidKorczynski marked this conversation as resolved.
Show resolved Hide resolved
fuzzedWithCLibFuzzer.Probe,
fuzzedWithCppLibFuzzer.Probe,
fuzzedWithRustCargofuzz.Probe,
fuzzedWithJavaJazzerFuzzer.Probe,
fuzzedWithOneFuzz.Probe,
fuzzedWithOSSFuzz.Probe,
fuzzedWithPropertyBasedHaskell.Probe,
Expand Down
40 changes: 40 additions & 0 deletions checks/evaluation/fuzzing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,26 @@ func TestFuzzing(t *testing.T) {
Probe: "fuzzedWithGoNative",
Outcome: finding.OutcomeNegative,
},
{
Probe: "fuzzedWithPythonAtheris",
Outcome: finding.OutcomeNegative,
},
{
Probe: "fuzzedWithCLibFuzzer",
Outcome: finding.OutcomeNegative,
},
{
Probe: "fuzzedWithCppLibFuzzer",
Outcome: finding.OutcomeNegative,
},
{
Probe: "fuzzedWithRustCargofuzz",
Outcome: finding.OutcomeNegative,
},
{
Probe: "fuzzedWithJavaJazzerFuzzer",
Outcome: finding.OutcomeNegative,
},
{
DavidKorczynski marked this conversation as resolved.
Show resolved Hide resolved
Probe: "fuzzedWithOneFuzz",
Outcome: finding.OutcomeNegative,
Expand Down Expand Up @@ -89,6 +109,26 @@ func TestFuzzing(t *testing.T) {
Probe: "fuzzedWithGoNative",
Outcome: finding.OutcomePositive,
},
{
Probe: "fuzzedWithPythonAtheris",
Outcome: finding.OutcomeNegative,
},
{
Probe: "fuzzedWithCLibFuzzer",
Outcome: finding.OutcomeNegative,
},
{
Probe: "fuzzedWithCppLibFuzzer",
Outcome: finding.OutcomeNegative,
},
{
Probe: "fuzzedWithRustCargofuzz",
Outcome: finding.OutcomeNegative,
},
{
Probe: "fuzzedWithJavaJazzerFuzzer",
Outcome: finding.OutcomeNegative,
},
{
Probe: "fuzzedWithOneFuzz",
Outcome: finding.OutcomeNegative,
Expand Down
4 changes: 0 additions & 4 deletions checks/fileparser/listing.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,6 @@ func OnMatchingFileContentDo(repoClient clients.RepoClient, matchPathTo PathMatc
onFileContent DoWhileTrueOnFileContent, args ...interface{},
) error {
predicate := func(filepath string) (bool, error) {
// Filter out test files.
if isTestdataFile(filepath) {
return false, nil
}
spencerschrock marked this conversation as resolved.
Show resolved Hide resolved
// Filter out files based on path/names using the pattern.
b, err := isMatchingPath(filepath, matchPathTo)
if err != nil {
Expand Down
8 changes: 4 additions & 4 deletions checks/fuzzing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func TestFuzzing(t *testing.T) {
wantErr: false,
expected: scut.TestReturn{
Error: nil,
NumberOfWarn: 7,
NumberOfWarn: 12,
NumberOfDebug: 0,
NumberOfInfo: 0,
Score: 0,
Expand All @@ -76,7 +76,7 @@ func TestFuzzing(t *testing.T) {
},
wantErr: false,
expected: scut.TestReturn{
NumberOfWarn: 6,
NumberOfWarn: 11,
spencerschrock marked this conversation as resolved.
Show resolved Hide resolved
NumberOfDebug: 0,
NumberOfInfo: 1,
Score: 10,
Expand Down Expand Up @@ -110,7 +110,7 @@ func TestFuzzing(t *testing.T) {
wantFuzzErr: false,
expected: scut.TestReturn{
Error: nil,
NumberOfWarn: 7,
NumberOfWarn: 12,
NumberOfDebug: 0,
NumberOfInfo: 0,
Score: 0,
Expand All @@ -121,7 +121,7 @@ func TestFuzzing(t *testing.T) {
wantFuzzErr: true,
expected: scut.TestReturn{
Error: nil,
NumberOfWarn: 7,
NumberOfWarn: 12,
NumberOfDebug: 0,
NumberOfInfo: 0,
Score: 0,
Expand Down
97 changes: 76 additions & 21 deletions checks/raw/fuzzing.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ const (
fuzzerPropertyBasedHaskell = "HaskellPropertyBasedTesting"
fuzzerPropertyBasedJavaScript = "JavaScriptPropertyBasedTesting"
fuzzerPropertyBasedTypeScript = "TypeScriptPropertyBasedTesting"
fuzzerPythonAtheris = "PythonAtherisFuzzer"
fuzzerCLibFuzzer = "CLibFuzzer"
fuzzerCppLibFuzzer = "CppLibFuzzer"
fuzzerRustCargoFuzz = "RustCargoFuzzer"
fuzzerJavaJazzerFuzzer = "JavaJazzerFuzzer"
// TODO: add more fuzzing check supports.
)

Expand All @@ -47,8 +52,8 @@ type filesWithPatternStr struct {
type languageFuzzConfig struct {
URL, Desc *string

// Pattern is according to path.Match.
filePattern string
// Patterns are according to path.Match.
filePatterns []string

funcPattern, Name string
// TODO: add more language fuzzing-related fields.
Expand All @@ -59,10 +64,10 @@ type languageFuzzConfig struct {
var languageFuzzSpecs = map[clients.LanguageName]languageFuzzConfig{
// Default fuzz patterns for Go.
clients.Go: {
filePattern: "*_test.go",
funcPattern: `func\s+Fuzz\w+\s*\(\w+\s+\*testing.F\)`,
Name: fuzzerBuiltInGo,
URL: asPointer("https://go.dev/doc/fuzz/"),
filePatterns: []string{"*_test.go"},
funcPattern: `func\s+Fuzz\w+\s*\(\w+\s+\*testing.F\)`,
Name: fuzzerBuiltInGo,
URL: asPointer("https://go.dev/doc/fuzz/"),
Desc: asPointer(
"Go fuzzing intelligently walks through the source code to report failures and find vulnerabilities."),
},
Expand All @@ -80,7 +85,7 @@ var languageFuzzSpecs = map[clients.LanguageName]languageFuzzConfig{
//
// This is not an exhaustive list.
clients.Haskell: {
filePattern: "*.hs",
filePatterns: []string{"*.hs"},
DavidKorczynski marked this conversation as resolved.
Show resolved Hide resolved
// Look for direct imports of QuickCheck, Hedgehog, validity, or SmallCheck,
// or their indirect imports through the higher-level Hspec or Tasty testing frameworks.
funcPattern: `import\s+(qualified\s+)?Test\.((Hspec|Tasty)\.)?(QuickCheck|Hedgehog|Validity|SmallCheck)`,
Expand All @@ -96,7 +101,7 @@ var languageFuzzSpecs = map[clients.LanguageName]languageFuzzConfig{
//
// This is not an exhaustive list.
clients.JavaScript: {
filePattern: "*.js",
filePatterns: []string{"*.js"},
// Look for direct imports of fast-check.
funcPattern: `(from\s+['"]fast-check['"]|require\(\s*['"]fast-check['"]\s*\))`,
Name: fuzzerPropertyBasedJavaScript,
Expand All @@ -105,14 +110,55 @@ var languageFuzzSpecs = map[clients.LanguageName]languageFuzzConfig{
"and test that specific properties are satisfied."),
},
clients.TypeScript: {
filePattern: "*.ts",
filePatterns: []string{"*.ts"},
spencerschrock marked this conversation as resolved.
Show resolved Hide resolved
// Look for direct imports of fast-check.
funcPattern: `(from\s+['"]fast-check['"]|require\(\s*['"]fast-check['"]\s*\))`,
Name: fuzzerPropertyBasedTypeScript,
Desc: asPointer(
"Property-based testing in TypeScript generates test instances randomly or exhaustively " +
"and test that specific properties are satisfied."),
},
clients.Python: {
filePatterns: []string{"*.py"},
// Look for direct imports of fast-check.
funcPattern: `import atheris`,
spencerschrock marked this conversation as resolved.
Show resolved Hide resolved
Name: fuzzerPythonAtheris,
Desc: asPointer(
"Python fuzzing by way of Atheris"),
},
clients.C: {
filePatterns: []string{"*.c"},
// Look for direct imports of fast-check.
funcPattern: `LLVMFuzzerTestOneInput`,
Name: fuzzerCLibFuzzer,
Desc: asPointer(
"Fuzzed with C LibFuzzer"),
},
clients.Cpp: {
filePatterns: []string{"*.cc", "*.cpp"},
// Look for direct imports of fast-check.
funcPattern: `LLVMFuzzerTestOneInput`,
Name: fuzzerCppLibFuzzer,
Desc: asPointer(
"Fuzzed with cpp LibFuzzer"),
},
clients.Rust: {
filePatterns: []string{"*.rs"},
// Look for direct imports of fast-check.
funcPattern: `libfuzzer_sys`,
Name: fuzzerRustCargoFuzz,
Desc: asPointer(
"Fuzzed with Cargo-fuzz"),
},
clients.Java: {
filePatterns: []string{"*.java"},
// Look for direct imports of fast-check.
funcPattern: `com.code_intelligence.jazzer.api.FuzzedDataProvider;`,
// funcPattern: `jazze`,
Name: fuzzerJavaJazzerFuzzer,
Desc: asPointer(
"Fuzzed with Jazzer fuzzer"),
},
// TODO: add more language-specific fuzz patterns & configs.
}

Expand Down Expand Up @@ -171,6 +217,7 @@ func Fuzzing(c *checker.CheckRequest) (checker.FuzzingData, error) {
prominentLangs := getProminentLanguages(langs)
for _, lang := range prominentLangs {
usingFuzzFunc, files, e := checkFuzzFunc(c, lang)
fmt.Print(files)
DavidKorczynski marked this conversation as resolved.
Show resolved Hide resolved
if e != nil {
return checker.FuzzingData{}, fmt.Errorf("%w", e)
}
Expand Down Expand Up @@ -254,22 +301,30 @@ func checkFuzzFunc(c *checker.CheckRequest, lang clients.LanguageName) (bool, []
// Get patterns for file and func.
// We use the file pattern in the matcher to match the test files,
// and put the func pattern in var data to match file contents (func names).
filePattern, funcPattern := pattern.filePattern, pattern.funcPattern
matcher := fileparser.PathMatcher{
Pattern: filePattern,
CaseSensitive: false,
}
data.pattern = funcPattern
err := fileparser.OnMatchingFileContentDo(c.RepoClient, matcher, getFuzzFunc, &data)
if err != nil {
return false, nil, fmt.Errorf("error when OnMatchingFileContentDo: %w", err)
filePatterns, funcPattern := pattern.filePatterns, pattern.funcPattern
dataFiles := []checker.File{}
DavidKorczynski marked this conversation as resolved.
Show resolved Hide resolved

for _, filePattern := range filePatterns {
matcher := fileparser.PathMatcher{
Pattern: filePattern,
CaseSensitive: false,
}
data.pattern = funcPattern
err := fileparser.OnMatchingFileContentDo(c.RepoClient, matcher, getFuzzFunc, &data)
if err != nil {
return false, nil, fmt.Errorf("error when OnMatchingFileContentDo: %w", err)
}
if len(data.files) != 0 {
DavidKorczynski marked this conversation as resolved.
Show resolved Hide resolved
dataFiles = append(dataFiles, data.files...)
// This means no fuzz funcs matched for this language.
}
}

if len(data.files) == 0 {
if len(dataFiles) == 0 {
// This means no fuzz funcs matched for this language.
return false, nil, nil
}
return true, data.files, nil
return true, dataFiles, nil
}

// This is the callback func for interface OnMatchingFileContentDo
Expand Down Expand Up @@ -322,7 +377,7 @@ func getProminentLanguages(langs []clients.Language) []clients.LanguageName {
// Languages that have lines of code above average will be considered prominent.
ret := []clients.LanguageName{}
for lName, loC := range langMap {
if loC >= avgLoC {
if loC >= avgLoC/4.0 {
spencerschrock marked this conversation as resolved.
Show resolved Hide resolved
lang := clients.LanguageName(strings.ToLower(string(lName)))
ret = append(ret, lang)
}
Expand Down
9 changes: 6 additions & 3 deletions checks/raw/fuzzing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,8 @@ func Test_fuzzFileAndFuncMatchPattern(t *testing.T) {
expectedFileMatch: false,
expectedFuncMatch: false,
lang: clients.LanguageName("not_a_supported_one"),
fileName: "a_fuzz_test.py",
fileContent: `def NotSupported (foo)`,
fileName: "a_fuzz_test.php",
fileContent: `function function-not-supported (foo)`,
wantErr: true,
},
}
Expand All @@ -274,7 +274,10 @@ func Test_fuzzFileAndFuncMatchPattern(t *testing.T) {
if !ok && !tt.wantErr {
t.Errorf("retrieve supported language error")
}
fileMatchPattern := langSpecs.filePattern
fileMatchPattern := ""
DavidKorczynski marked this conversation as resolved.
Show resolved Hide resolved
if len(langSpecs.filePatterns) > 0 {
fileMatchPattern = langSpecs.filePatterns[0]
}
fileMatch, err := path.Match(fileMatchPattern, tt.fileName)
if (fileMatch != tt.expectedFileMatch || err != nil) && !tt.wantErr {
t.Errorf("fileMatch = %v, want %v for %v", fileMatch, tt.expectedFileMatch, tt.name)
Expand Down
10 changes: 10 additions & 0 deletions probes/entries.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,18 @@ package probes
import (
"github.com/ossf/scorecard/v4/checker"
"github.com/ossf/scorecard/v4/finding"
"github.com/ossf/scorecard/v4/probes/fuzzedWithCLibFuzzer"
"github.com/ossf/scorecard/v4/probes/fuzzedWithClusterFuzzLite"
"github.com/ossf/scorecard/v4/probes/fuzzedWithCppLibFuzzer"
"github.com/ossf/scorecard/v4/probes/fuzzedWithGoNative"
"github.com/ossf/scorecard/v4/probes/fuzzedWithJavaJazzerFuzzer"
"github.com/ossf/scorecard/v4/probes/fuzzedWithOSSFuzz"
"github.com/ossf/scorecard/v4/probes/fuzzedWithOneFuzz"
"github.com/ossf/scorecard/v4/probes/fuzzedWithPropertyBasedHaskell"
"github.com/ossf/scorecard/v4/probes/fuzzedWithPropertyBasedJavascript"
"github.com/ossf/scorecard/v4/probes/fuzzedWithPropertyBasedTypescript"
"github.com/ossf/scorecard/v4/probes/fuzzedWithPythonAtheris"
"github.com/ossf/scorecard/v4/probes/fuzzedWithRustCargofuzz"
"github.com/ossf/scorecard/v4/probes/securityPolicyContainsLinks"
"github.com/ossf/scorecard/v4/probes/securityPolicyContainsText"
"github.com/ossf/scorecard/v4/probes/securityPolicyContainsVulnerabilityDisclosure"
Expand Down Expand Up @@ -60,6 +65,11 @@ var (
fuzzedWithOSSFuzz.Run,
fuzzedWithOneFuzz.Run,
fuzzedWithGoNative.Run,
fuzzedWithPythonAtheris.Run,
fuzzedWithCLibFuzzer.Run,
fuzzedWithCppLibFuzzer.Run,
fuzzedWithRustCargofuzz.Run,
fuzzedWithJavaJazzerFuzzer.Run,
fuzzedWithClusterFuzzLite.Run,
fuzzedWithPropertyBasedHaskell.Run,
fuzzedWithPropertyBasedTypescript.Run,
Expand Down
32 changes: 32 additions & 0 deletions probes/fuzzedWithCLibFuzzer/def.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Copyright 2023 OpenSSF Scorecard Authors
#
# 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.

id: fuzzedWithCLibFuzzer
short: Check that the project is fuzzed using LibFuzzer
motivation: >
Fuzzing, or fuzz testing, is the practice of feeding unexpected or random data into a program to expose bugs.
Regular fuzzing is important to detect vulnerabilities that may be exploited by others, especially since attackers can also use fuzzing to find the same flaws.
implementation: >
The implementation checks whether fo the presence of functions with the signature 'LLVMFuzzerTestOneInput' in .c files.
outcome:
- If fuzzing functions are found, each finding is returned with OutcomePositive (1).
- If no fuzzing is detected, one finding with OutcomeNegative (0) is returned.
remediation:
effort: Medium
text:
- Follow the steps in https://llvm.org/docs/LibFuzzer.html to enable fuzzing on your project.
- Over time, try to add fuzzing for more functionalities of your project.
markdown:
- Follow the steps in [https://llvm.org/docs/LibFuzzer.html](https://llvm.org/docs/LibFuzzer.html) to enable fuzzing on your project.
- Over time, try to add fuzzing for more functionalities of your project.
Loading
Loading