blob: ccadc0ff2cb7c390f29856e7b04e0092d12d5a25 [file] [log] [blame]
hamzeh41ad8812021-07-07 14:00:07 -07001// Copyright 2021 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
hamzehc0a671f2021-07-22 12:05:08 -070015package fuzz
hamzeh41ad8812021-07-07 14:00:07 -070016
17// This file contains the common code for compiling C/C++ and Rust fuzzers for Android.
18
19import (
hamzehc0a671f2021-07-22 12:05:08 -070020 "encoding/json"
hamzeh41ad8812021-07-07 14:00:07 -070021 "sort"
22 "strings"
23
hamzehc0a671f2021-07-22 12:05:08 -070024 "github.com/google/blueprint/proptools"
25
hamzeh41ad8812021-07-07 14:00:07 -070026 "android/soong/android"
27)
28
29type Lang string
30
31const (
32 Cc Lang = ""
33 Rust Lang = "rust"
34)
35
hamzehc0a671f2021-07-22 12:05:08 -070036var BoolDefault = proptools.BoolDefault
37
hamzeh41ad8812021-07-07 14:00:07 -070038type FuzzModule struct {
39 android.ModuleBase
40 android.DefaultableModuleBase
41 android.ApexModuleBase
42}
43
44type FuzzPackager struct {
45 Packages android.Paths
46 FuzzTargets map[string]bool
47}
48
49type FileToZip struct {
50 SourceFilePath android.Path
51 DestinationPathPrefix string
52}
53
54type ArchOs struct {
55 HostOrTarget string
56 Arch string
57 Dir string
58}
59
hamzehc0a671f2021-07-22 12:05:08 -070060type FuzzConfig struct {
61 // Email address of people to CC on bugs or contact about this fuzz target.
62 Cc []string `json:"cc,omitempty"`
63 // Specify whether to enable continuous fuzzing on devices. Defaults to true.
64 Fuzz_on_haiku_device *bool `json:"fuzz_on_haiku_device,omitempty"`
65 // Specify whether to enable continuous fuzzing on host. Defaults to true.
66 Fuzz_on_haiku_host *bool `json:"fuzz_on_haiku_host,omitempty"`
67 // Component in Google's bug tracking system that bugs should be filed to.
68 Componentid *int64 `json:"componentid,omitempty"`
69 // Hotlists in Google's bug tracking system that bugs should be marked with.
70 Hotlists []string `json:"hotlists,omitempty"`
71 // Specify whether this fuzz target was submitted by a researcher. Defaults
72 // to false.
73 Researcher_submitted *bool `json:"researcher_submitted,omitempty"`
74 // Specify who should be acknowledged for CVEs in the Android Security
75 // Bulletin.
76 Acknowledgement []string `json:"acknowledgement,omitempty"`
77 // Additional options to be passed to libfuzzer when run in Haiku.
78 Libfuzzer_options []string `json:"libfuzzer_options,omitempty"`
79 // Additional options to be passed to HWASAN when running on-device in Haiku.
80 Hwasan_options []string `json:"hwasan_options,omitempty"`
81 // Additional options to be passed to HWASAN when running on host in Haiku.
82 Asan_options []string `json:"asan_options,omitempty"`
83}
84
85type FuzzProperties struct {
86 // Optional list of seed files to be installed to the fuzz target's output
87 // directory.
88 Corpus []string `android:"path"`
89 // Optional list of data files to be installed to the fuzz target's output
90 // directory. Directory structure relative to the module is preserved.
91 Data []string `android:"path"`
92 // Optional dictionary to be installed to the fuzz target's output directory.
93 Dictionary *string `android:"path"`
94 // Config for running the target on fuzzing infrastructure.
95 Fuzz_config *FuzzConfig
96}
97
hamzeh41ad8812021-07-07 14:00:07 -070098type FuzzPackagedModule struct {
99 FuzzProperties FuzzProperties
100 Dictionary android.Path
101 Corpus android.Paths
102 CorpusIntermediateDir android.Path
103 Config android.Path
104 Data android.Paths
105 DataIntermediateDir android.Path
106}
107
108func IsValid(fuzzModule FuzzModule) bool {
109 // Discard ramdisk + vendor_ramdisk + recovery modules, they're duplicates of
110 // fuzz targets we're going to package anyway.
111 if !fuzzModule.Enabled() || fuzzModule.InRamdisk() || fuzzModule.InVendorRamdisk() || fuzzModule.InRecovery() {
112 return false
113 }
114
115 // Discard modules that are in an unavailable namespace.
116 if !fuzzModule.ExportedToMake() {
117 return false
118 }
119
120 return true
121}
122
123func (s *FuzzPackager) PackageArtifacts(ctx android.SingletonContext, module android.Module, fuzzModule FuzzPackagedModule, archDir android.OutputPath, builder *android.RuleBuilder) []FileToZip {
124 // Package the corpora into a zipfile.
125 var files []FileToZip
126 if fuzzModule.Corpus != nil {
127 corpusZip := archDir.Join(ctx, module.Name()+"_seed_corpus.zip")
128 command := builder.Command().BuiltTool("soong_zip").
129 Flag("-j").
130 FlagWithOutput("-o ", corpusZip)
131 rspFile := corpusZip.ReplaceExtension(ctx, "rsp")
132 command.FlagWithRspFileInputList("-r ", rspFile, fuzzModule.Corpus)
133 files = append(files, FileToZip{corpusZip, ""})
134 }
135
136 // Package the data into a zipfile.
137 if fuzzModule.Data != nil {
138 dataZip := archDir.Join(ctx, module.Name()+"_data.zip")
139 command := builder.Command().BuiltTool("soong_zip").
140 FlagWithOutput("-o ", dataZip)
141 for _, f := range fuzzModule.Data {
142 intermediateDir := strings.TrimSuffix(f.String(), f.Rel())
143 command.FlagWithArg("-C ", intermediateDir)
144 command.FlagWithInput("-f ", f)
145 }
146 files = append(files, FileToZip{dataZip, ""})
147 }
148
149 // The dictionary.
150 if fuzzModule.Dictionary != nil {
151 files = append(files, FileToZip{fuzzModule.Dictionary, ""})
152 }
153
154 // Additional fuzz config.
155 if fuzzModule.Config != nil {
156 files = append(files, FileToZip{fuzzModule.Config, ""})
157 }
158
159 return files
160}
161
162func (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) {
163 fuzzZip := archDir.Join(ctx, module.Name()+".zip")
164
165 command := builder.Command().BuiltTool("soong_zip").
166 Flag("-j").
167 FlagWithOutput("-o ", fuzzZip)
168
169 for _, file := range files {
170 if file.DestinationPathPrefix != "" {
171 command.FlagWithArg("-P ", file.DestinationPathPrefix)
172 } else {
173 command.Flag("-P ''")
174 }
175 command.FlagWithInput("-f ", file.SourceFilePath)
176 }
177
178 builder.Build("create-"+fuzzZip.String(),
179 "Package "+module.Name()+" for "+archString+"-"+hostOrTargetString)
180
181 // Don't add modules to 'make haiku-rust' that are set to not be
182 // exported to the fuzzing infrastructure.
183 if config := fuzzModule.FuzzProperties.Fuzz_config; config != nil {
184 if strings.Contains(hostOrTargetString, "host") && !BoolDefault(config.Fuzz_on_haiku_host, true) {
185 return archDirs[archOs], false
186 } else if !BoolDefault(config.Fuzz_on_haiku_device, true) {
187 return archDirs[archOs], false
188 }
189 }
190
191 s.FuzzTargets[module.Name()] = true
192 archDirs[archOs] = append(archDirs[archOs], FileToZip{fuzzZip, ""})
193
194 return archDirs[archOs], true
195}
196
hamzehc0a671f2021-07-22 12:05:08 -0700197func (f *FuzzConfig) String() string {
198 b, err := json.Marshal(f)
199 if err != nil {
200 panic(err)
201 }
202
203 return string(b)
204}
205
206func (s *FuzzPackager) CreateFuzzPackage(ctx android.SingletonContext, archDirs map[ArchOs][]FileToZip, lang Lang, pctx android.PackageContext) {
hamzeh41ad8812021-07-07 14:00:07 -0700207 var archOsList []ArchOs
208 for archOs := range archDirs {
209 archOsList = append(archOsList, archOs)
210 }
211 sort.Slice(archOsList, func(i, j int) bool { return archOsList[i].Dir < archOsList[j].Dir })
212
213 for _, archOs := range archOsList {
214 filesToZip := archDirs[archOs]
215 arch := archOs.Arch
216 hostOrTarget := archOs.HostOrTarget
217 builder := android.NewRuleBuilder(pctx, ctx)
218 zipFileName := "fuzz-" + hostOrTarget + "-" + arch + ".zip"
219 if lang == Rust {
220 zipFileName = "fuzz-rust-" + hostOrTarget + "-" + arch + ".zip"
221 }
222 outputFile := android.PathForOutput(ctx, zipFileName)
223
224 s.Packages = append(s.Packages, outputFile)
225
226 command := builder.Command().BuiltTool("soong_zip").
227 Flag("-j").
228 FlagWithOutput("-o ", outputFile).
229 Flag("-L 0") // No need to try and re-compress the zipfiles.
230
231 for _, fileToZip := range filesToZip {
232
233 if fileToZip.DestinationPathPrefix != "" {
234 command.FlagWithArg("-P ", fileToZip.DestinationPathPrefix)
235 } else {
236 command.Flag("-P ''")
237 }
238 command.FlagWithInput("-f ", fileToZip.SourceFilePath)
239
240 }
241 builder.Build("create-fuzz-package-"+arch+"-"+hostOrTarget,
242 "Create fuzz target packages for "+arch+"-"+hostOrTarget)
243 }
244}
245
246func (s *FuzzPackager) PreallocateSlice(ctx android.MakeVarsContext, targets string) {
247 fuzzTargets := make([]string, 0, len(s.FuzzTargets))
248 for target, _ := range s.FuzzTargets {
249 fuzzTargets = append(fuzzTargets, target)
250 }
251 sort.Strings(fuzzTargets)
252 ctx.Strict(targets, strings.Join(fuzzTargets, " "))
253}