diff options
author | 2021-07-22 12:05:08 -0700 | |
---|---|---|
committer | 2021-08-11 23:54:15 +0000 | |
commit | c0a671fc80264fdf501225f64f8c2605d48d77ca (patch) | |
tree | dfea6dc68b37ede6ac0d8269c136966120d37d4d /fuzz/fuzz_common.go | |
parent | 60880e05176a6f6b39ed38657d1c32ad178a17e8 (diff) |
Moving common fuzzing code to fuzz package
Test: make haiku and make haiku-rust
Change-Id: Ife80cc10672f51bd6afbae7061cc9373a2a15e7d
Diffstat (limited to 'fuzz/fuzz_common.go')
-rw-r--r-- | fuzz/fuzz_common.go | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/fuzz/fuzz_common.go b/fuzz/fuzz_common.go new file mode 100644 index 000000000..ccadc0ff2 --- /dev/null +++ b/fuzz/fuzz_common.go @@ -0,0 +1,253 @@ +// Copyright 2021 Google Inc. All rights reserved. +// +// 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 fuzz + +// This file contains the common code for compiling C/C++ and Rust fuzzers for Android. + +import ( + "encoding/json" + "sort" + "strings" + + "github.com/google/blueprint/proptools" + + "android/soong/android" +) + +type Lang string + +const ( + Cc Lang = "" + Rust Lang = "rust" +) + +var BoolDefault = proptools.BoolDefault + +type FuzzModule struct { + android.ModuleBase + android.DefaultableModuleBase + android.ApexModuleBase +} + +type FuzzPackager struct { + Packages android.Paths + FuzzTargets map[string]bool +} + +type FileToZip struct { + SourceFilePath android.Path + DestinationPathPrefix string +} + +type ArchOs struct { + HostOrTarget string + Arch string + Dir string +} + +type FuzzConfig struct { + // Email address of people to CC on bugs or contact about this fuzz target. + Cc []string `json:"cc,omitempty"` + // Specify whether to enable continuous fuzzing on devices. Defaults to true. + Fuzz_on_haiku_device *bool `json:"fuzz_on_haiku_device,omitempty"` + // Specify whether to enable continuous fuzzing on host. Defaults to true. + Fuzz_on_haiku_host *bool `json:"fuzz_on_haiku_host,omitempty"` + // Component in Google's bug tracking system that bugs should be filed to. + Componentid *int64 `json:"componentid,omitempty"` + // Hotlists in Google's bug tracking system that bugs should be marked with. + Hotlists []string `json:"hotlists,omitempty"` + // Specify whether this fuzz target was submitted by a researcher. Defaults + // to false. + Researcher_submitted *bool `json:"researcher_submitted,omitempty"` + // Specify who should be acknowledged for CVEs in the Android Security + // Bulletin. + Acknowledgement []string `json:"acknowledgement,omitempty"` + // Additional options to be passed to libfuzzer when run in Haiku. + Libfuzzer_options []string `json:"libfuzzer_options,omitempty"` + // Additional options to be passed to HWASAN when running on-device in Haiku. + Hwasan_options []string `json:"hwasan_options,omitempty"` + // Additional options to be passed to HWASAN when running on host in Haiku. + Asan_options []string `json:"asan_options,omitempty"` +} + +type FuzzProperties struct { + // Optional list of seed files to be installed to the fuzz target's output + // directory. + Corpus []string `android:"path"` + // Optional list of data files to be installed to the fuzz target's output + // directory. Directory structure relative to the module is preserved. + Data []string `android:"path"` + // Optional dictionary to be installed to the fuzz target's output directory. + Dictionary *string `android:"path"` + // Config for running the target on fuzzing infrastructure. + Fuzz_config *FuzzConfig +} + +type FuzzPackagedModule struct { + FuzzProperties FuzzProperties + Dictionary android.Path + Corpus android.Paths + CorpusIntermediateDir android.Path + Config android.Path + Data android.Paths + DataIntermediateDir android.Path +} + +func IsValid(fuzzModule FuzzModule) bool { + // Discard ramdisk + vendor_ramdisk + recovery modules, they're duplicates of + // fuzz targets we're going to package anyway. + if !fuzzModule.Enabled() || fuzzModule.InRamdisk() || fuzzModule.InVendorRamdisk() || fuzzModule.InRecovery() { + return false + } + + // Discard modules that are in an unavailable namespace. + if !fuzzModule.ExportedToMake() { + return false + } + + return true +} + +func (s *FuzzPackager) PackageArtifacts(ctx android.SingletonContext, module android.Module, fuzzModule FuzzPackagedModule, archDir android.OutputPath, builder *android.RuleBuilder) []FileToZip { + // Package the corpora into a zipfile. + var files []FileToZip + if fuzzModule.Corpus != nil { + corpusZip := archDir.Join(ctx, module.Name()+"_seed_corpus.zip") + command := builder.Command().BuiltTool("soong_zip"). + Flag("-j"). + FlagWithOutput("-o ", corpusZip) + rspFile := corpusZip.ReplaceExtension(ctx, "rsp") + command.FlagWithRspFileInputList("-r ", rspFile, fuzzModule.Corpus) + files = append(files, FileToZip{corpusZip, ""}) + } + + // Package the data into a zipfile. + if fuzzModule.Data != nil { + dataZip := archDir.Join(ctx, module.Name()+"_data.zip") + command := builder.Command().BuiltTool("soong_zip"). + FlagWithOutput("-o ", dataZip) + for _, f := range fuzzModule.Data { + intermediateDir := strings.TrimSuffix(f.String(), f.Rel()) + command.FlagWithArg("-C ", intermediateDir) + command.FlagWithInput("-f ", f) + } + files = append(files, FileToZip{dataZip, ""}) + } + + // The dictionary. + if fuzzModule.Dictionary != nil { + files = append(files, FileToZip{fuzzModule.Dictionary, ""}) + } + + // Additional fuzz config. + if fuzzModule.Config != nil { + files = append(files, FileToZip{fuzzModule.Config, ""}) + } + + return files +} + +func (s *FuzzPackager) BuildZipFile(ctx android.SingletonContext, module android.Module, fuzzModule FuzzPackagedModule, files []FileToZip, builder *android.RuleBuilder, archDir android.OutputPath, archString string, hostOrTargetString string, archOs ArchOs, archDirs map[ArchOs][]FileToZip) ([]FileToZip, bool) { + fuzzZip := archDir.Join(ctx, module.Name()+".zip") + + command := builder.Command().BuiltTool("soong_zip"). + Flag("-j"). + FlagWithOutput("-o ", fuzzZip) + + for _, file := range files { + if file.DestinationPathPrefix != "" { + command.FlagWithArg("-P ", file.DestinationPathPrefix) + } else { + command.Flag("-P ''") + } + command.FlagWithInput("-f ", file.SourceFilePath) + } + + builder.Build("create-"+fuzzZip.String(), + "Package "+module.Name()+" for "+archString+"-"+hostOrTargetString) + + // Don't add modules to 'make haiku-rust' that are set to not be + // exported to the fuzzing infrastructure. + if config := fuzzModule.FuzzProperties.Fuzz_config; config != nil { + if strings.Contains(hostOrTargetString, "host") && !BoolDefault(config.Fuzz_on_haiku_host, true) { + return archDirs[archOs], false + } else if !BoolDefault(config.Fuzz_on_haiku_device, true) { + return archDirs[archOs], false + } + } + + s.FuzzTargets[module.Name()] = true + archDirs[archOs] = append(archDirs[archOs], FileToZip{fuzzZip, ""}) + + return archDirs[archOs], true +} + +func (f *FuzzConfig) String() string { + b, err := json.Marshal(f) + if err != nil { + panic(err) + } + + return string(b) +} + +func (s *FuzzPackager) CreateFuzzPackage(ctx android.SingletonContext, archDirs map[ArchOs][]FileToZip, lang Lang, pctx android.PackageContext) { + var archOsList []ArchOs + for archOs := range archDirs { + archOsList = append(archOsList, archOs) + } + sort.Slice(archOsList, func(i, j int) bool { return archOsList[i].Dir < archOsList[j].Dir }) + + for _, archOs := range archOsList { + filesToZip := archDirs[archOs] + arch := archOs.Arch + hostOrTarget := archOs.HostOrTarget + builder := android.NewRuleBuilder(pctx, ctx) + zipFileName := "fuzz-" + hostOrTarget + "-" + arch + ".zip" + if lang == Rust { + zipFileName = "fuzz-rust-" + hostOrTarget + "-" + arch + ".zip" + } + outputFile := android.PathForOutput(ctx, zipFileName) + + s.Packages = append(s.Packages, outputFile) + + command := builder.Command().BuiltTool("soong_zip"). + Flag("-j"). + FlagWithOutput("-o ", outputFile). + Flag("-L 0") // No need to try and re-compress the zipfiles. + + for _, fileToZip := range filesToZip { + + if fileToZip.DestinationPathPrefix != "" { + command.FlagWithArg("-P ", fileToZip.DestinationPathPrefix) + } else { + command.Flag("-P ''") + } + command.FlagWithInput("-f ", fileToZip.SourceFilePath) + + } + builder.Build("create-fuzz-package-"+arch+"-"+hostOrTarget, + "Create fuzz target packages for "+arch+"-"+hostOrTarget) + } +} + +func (s *FuzzPackager) PreallocateSlice(ctx android.MakeVarsContext, targets string) { + fuzzTargets := make([]string, 0, len(s.FuzzTargets)) + for target, _ := range s.FuzzTargets { + fuzzTargets = append(fuzzTargets, target) + } + sort.Strings(fuzzTargets) + ctx.Strict(targets, strings.Join(fuzzTargets, " ")) +} |