blob: f08378d6797a4eb15bc09d691022138bea2919f9 [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"
hamzehe8a1bfa2022-06-21 12:22:06 -070021 "fmt"
hamzeh41ad8812021-07-07 14:00:07 -070022 "sort"
23 "strings"
24
Yu Liu119d38c2025-02-25 22:25:11 +000025 "github.com/google/blueprint"
hamzehc0a671f2021-07-22 12:05:08 -070026 "github.com/google/blueprint/proptools"
27
hamzeh41ad8812021-07-07 14:00:07 -070028 "android/soong/android"
29)
30
Cory Barker9cfcf6d2022-07-22 17:22:02 +000031type Lang string
hamzeh41ad8812021-07-07 14:00:07 -070032
33const (
Cory Barker9cfcf6d2022-07-22 17:22:02 +000034 Cc Lang = "cc"
35 Rust Lang = "rust"
36 Java Lang = "java"
37)
38
39type Framework string
40
41const (
42 AFL Framework = "afl"
43 LibFuzzer Framework = "libfuzzer"
44 Jazzer Framework = "jazzer"
45 UnknownFramework Framework = "unknownframework"
hamzeh41ad8812021-07-07 14:00:07 -070046)
47
Colin Cross597bad62024-10-08 15:10:55 -070048func (f Framework) Variant() string {
49 switch f {
50 case AFL:
51 return "afl"
52 case LibFuzzer:
53 return "libfuzzer"
54 case Jazzer:
55 return "jazzer"
56 default:
57 panic(fmt.Errorf("unknown fuzzer %q when getting variant", f))
58 }
59}
60
61func FrameworkFromVariant(v string) Framework {
62 switch v {
63 case "afl":
64 return AFL
65 case "libfuzzer":
66 return LibFuzzer
67 case "jazzer":
68 return Jazzer
69 default:
70 panic(fmt.Errorf("unknown variant %q when getting fuzzer", v))
71 }
72}
73
hamzehc0a671f2021-07-22 12:05:08 -070074var BoolDefault = proptools.BoolDefault
75
hamzeh41ad8812021-07-07 14:00:07 -070076type FuzzModule struct {
77 android.ModuleBase
78 android.DefaultableModuleBase
79 android.ApexModuleBase
80}
81
82type FuzzPackager struct {
Ivan Lozano39b0bf02021-10-14 12:22:09 -040083 Packages android.Paths
84 FuzzTargets map[string]bool
85 SharedLibInstallStrings []string
hamzeh41ad8812021-07-07 14:00:07 -070086}
87
88type FileToZip struct {
89 SourceFilePath android.Path
90 DestinationPathPrefix string
Colin Cross80462dc2023-05-08 15:09:31 -070091 DestinationPath string
hamzeh41ad8812021-07-07 14:00:07 -070092}
93
94type ArchOs struct {
95 HostOrTarget string
96 Arch string
97 Dir string
98}
99
hamzeheea256b2023-02-09 13:22:09 -0800100type Vector string
hamzehe8a1bfa2022-06-21 12:22:06 -0700101
102const (
hamzeheea256b2023-02-09 13:22:09 -0800103 unknown_access_vector Vector = "unknown_access_vector"
104 // The code being fuzzed is reachable from a remote source, or using data
105 // provided by a remote source. For example: media codecs process media files
106 // from the internet, SMS processing handles remote message data.
107 // See
108 // https://source.android.com/docs/security/overview/updates-resources#local-vs-remote
109 // for an explanation of what's considered "remote."
110 remote = "remote"
111 // The code being fuzzed can only be reached locally, such as from an
112 // installed app. As an example, if it's fuzzing a Binder interface, it's
113 // assumed that you'd need a local app to make arbitrary Binder calls.
114 // And the app that's calling the fuzzed code does not require any privileges;
115 // any 3rd party app could make these calls.
116 local_no_privileges_required = "local_no_privileges_required"
117 // The code being fuzzed can only be called locally, and the calling process
118 // requires additional permissions that prevent arbitrary 3rd party apps from
119 // calling the code. For instance: this requires a privileged or signature
120 // permission to reach, or SELinux restrictions prevent the untrusted_app
121 // domain from calling it.
122 local_privileges_required = "local_privileges_required"
123 // The code is only callable on a PC host, not on a production Android device.
124 // For instance, this is fuzzing code used during the build process, or
125 // tooling that does not exist on a user's actual Android device.
126 host_access = "host_access"
127 // The code being fuzzed is only reachable if the user has enabled Developer
128 // Options, or has enabled a persistent Developer Options setting.
129 local_with_developer_options = "local_with_developer_options"
hamzehe8a1bfa2022-06-21 12:22:06 -0700130)
131
hamzeheea256b2023-02-09 13:22:09 -0800132func (vector Vector) isValidVector() bool {
133 switch vector {
134 case "",
135 unknown_access_vector,
136 remote,
137 local_no_privileges_required,
138 local_privileges_required,
139 host_access,
140 local_with_developer_options:
141 return true
142 }
143 return false
144}
145
146type ServicePrivilege string
147
148const (
149 unknown_service_privilege ServicePrivilege = "unknown_service_privilege"
150 // The code being fuzzed runs on a Secure Element. This has access to some
151 // of the most privileged data on the device, such as authentication keys.
152 // Not all devices have a Secure Element.
153 secure_element = "secure_element"
154 // The code being fuzzed runs in the TEE. The TEE is designed to be resistant
155 // to a compromised kernel, and stores sensitive data.
156 trusted_execution = "trusted_execution"
157 // The code being fuzzed has privileges beyond what arbitrary 3rd party apps
158 // have. For instance, it's running as the System UID, or it's in an SELinux
159 // domain that's able to perform calls that can't be made by 3rd party apps.
160 privileged = "privileged"
161 // The code being fuzzed is equivalent to a 3rd party app. It runs in the
162 // untrusted_app SELinux domain, or it only has privileges that are equivalent
163 // to what a 3rd party app could have.
164 unprivileged = "unprivileged"
165 // The code being fuzzed is significantly constrained, and even if it's
166 // compromised, it has significant restrictions that prevent it from
167 // performing most actions. This is significantly more restricted than
168 // UNPRIVILEGED. An example is the isolatedProcess=true setting in a 3rd
169 // party app. Or a process that's very restricted by SELinux, such as
170 // anything in the mediacodec SELinux domain.
171 constrained = "constrained"
172 // The code being fuzzed always has Negligible Security Impact. Even
173 // arbitrary out of bounds writes and full code execution would not be
174 // considered a security vulnerability. This typically only makes sense if
175 // FuzzedCodeUsage is set to FUTURE_VERSION or EXPERIMENTAL, and if
176 // AutomaticallyRouteTo is set to ALWAYS_NSI.
177 nsi = "nsi"
178 // The code being fuzzed only runs on a PC host, not on a production Android
179 // device. For instance, the fuzzer is fuzzing code used during the build
180 // process, or tooling that does not exist on a user's actual Android device.
181 host_only = "host_only"
182)
183
184func (service_privilege ServicePrivilege) isValidServicePrivilege() bool {
185 switch service_privilege {
186 case "",
187 unknown_service_privilege,
188 secure_element,
189 trusted_execution,
190 privileged,
191 unprivileged,
192 constrained,
193 nsi,
194 host_only:
195 return true
196 }
197 return false
198}
199
Markf736b922023-05-08 22:11:44 +0000200type UsePlatformLibs string
201
202const (
203 unknown_use_platform_libs UsePlatformLibs = "unknown_use_platform_libs"
204 // Use the native libraries on the device, typically in /system directory
205 use_platform_libs = "use_platform_libs"
206 // Do not use any native libraries (ART will not be initialized)
207 use_none = "use_none"
208)
209
210func (use_platform_libs UsePlatformLibs) isValidUsePlatformLibs() bool {
211 switch use_platform_libs {
212 case "",
213 unknown_use_platform_libs,
214 use_platform_libs,
215 use_none:
216 return true
217 }
218 return false
219}
220
hamzeheea256b2023-02-09 13:22:09 -0800221type UserData string
222
223const (
224 unknown_user_data UserData = "unknown_user_data"
225 // The process being fuzzed only handles data from a single user, or from a
226 // single process or app. It's possible the process shuts down before
227 // handling data from another user/process/app, or it's possible the process
228 // only ever handles one user's/process's/app's data. As an example, some
229 // print spooler processes are started for a single document and terminate
230 // when done, so each instance only handles data from a single user/app.
231 single_user = "single_user"
232 // The process handles data from multiple users, or from multiple other apps
233 // or processes. Media processes, for instance, can handle media requests
234 // from multiple different apps without restarting. Wi-Fi and network
235 // processes handle data from multiple users, and processes, and apps.
236 multi_user = "multi_user"
237)
238
239func (user_data UserData) isValidUserData() bool {
240 switch user_data {
241 case "",
242 unknown_user_data,
243 single_user,
244 multi_user:
245 return true
246 }
247 return false
248}
249
250type FuzzedCodeUsage string
251
252const (
253 undefined FuzzedCodeUsage = "undefined"
254 unknown = "unknown"
255 // The code being fuzzed exists in a shipped version of Android and runs on
256 // devices in production.
257 shipped = "shipped"
258 // The code being fuzzed is not yet in a shipping version of Android, but it
259 // will be at some point in the future.
260 future_version = "future_version"
261 // The code being fuzzed is not in a shipping version of Android, and there
262 // are no plans to ship it in the future.
263 experimental = "experimental"
264)
265
266func (fuzzed_code_usage FuzzedCodeUsage) isValidFuzzedCodeUsage() bool {
267 switch fuzzed_code_usage {
268 case "",
269 undefined,
270 unknown,
271 shipped,
272 future_version,
273 experimental:
274 return true
275 }
276 return false
277}
278
279type AutomaticallyRouteTo string
280
281const (
282 undefined_routing AutomaticallyRouteTo = "undefined_routing"
283 // Automatically route this to the Android Automotive security team for
284 // assessment.
285 android_automotive = "android_automotive"
286 // This should not be used in fuzzer configurations. It is used internally
287 // by Severity Assigner to flag memory leak reports.
288 memory_leak = "memory_leak"
289 // Route this vulnerability to our Ittiam vendor team for assessment.
290 ittiam = "ittiam"
291 // Reports from this fuzzer are always NSI (see the NSI ServicePrivilegeEnum
292 // value for additional context). It is not possible for this code to ever
293 // have a security vulnerability.
294 always_nsi = "always_nsi"
295 // Route this vulnerability to AIDL team for assessment.
296 aidl = "aidl"
297)
298
299func (automatically_route_to AutomaticallyRouteTo) isValidAutomaticallyRouteTo() bool {
300 switch automatically_route_to {
301 case "",
302 undefined_routing,
303 android_automotive,
304 memory_leak,
305 ittiam,
306 always_nsi,
307 aidl:
308 return true
309 }
310 return false
311}
312
Yu Liu119d38c2025-02-25 22:25:11 +0000313func IsValidConfig(fuzzModule *FuzzPackagedModuleInfo, moduleName string) bool {
314 var config = fuzzModule.FuzzConfig
hamzehe8a1bfa2022-06-21 12:22:06 -0700315 if config != nil {
hamzeheea256b2023-02-09 13:22:09 -0800316 if !config.Vector.isValidVector() {
317 panic(fmt.Errorf("Invalid vector in fuzz config in %s", moduleName))
hamzehe8a1bfa2022-06-21 12:22:06 -0700318 }
hamzeheea256b2023-02-09 13:22:09 -0800319
Yu Liu119d38c2025-02-25 22:25:11 +0000320 if !config.ServicePrivilege.isValidServicePrivilege() {
hamzeheea256b2023-02-09 13:22:09 -0800321 panic(fmt.Errorf("Invalid service_privilege in fuzz config in %s", moduleName))
322 }
323
324 if !config.Users.isValidUserData() {
325 panic(fmt.Errorf("Invalid users (user_data) in fuzz config in %s", moduleName))
326 }
327
Yu Liu119d38c2025-02-25 22:25:11 +0000328 if !config.FuzzedCodeUsage.isValidFuzzedCodeUsage() {
hamzeheea256b2023-02-09 13:22:09 -0800329 panic(fmt.Errorf("Invalid fuzzed_code_usage in fuzz config in %s", moduleName))
330 }
331
Yu Liu119d38c2025-02-25 22:25:11 +0000332 if !config.AutomaticallyRouteTo.isValidAutomaticallyRouteTo() {
hamzeheea256b2023-02-09 13:22:09 -0800333 panic(fmt.Errorf("Invalid automatically_route_to in fuzz config in %s", moduleName))
334 }
Markf736b922023-05-08 22:11:44 +0000335
Yu Liu119d38c2025-02-25 22:25:11 +0000336 if !config.UsePlatformLibs.isValidUsePlatformLibs() {
Markf736b922023-05-08 22:11:44 +0000337 panic(fmt.Errorf("Invalid use_platform_libs in fuzz config in %s", moduleName))
338 }
hamzehe8a1bfa2022-06-21 12:22:06 -0700339 }
hamzeheea256b2023-02-09 13:22:09 -0800340 return true
hamzehe8a1bfa2022-06-21 12:22:06 -0700341}
342
hamzehc0a671f2021-07-22 12:05:08 -0700343type FuzzConfig struct {
344 // Email address of people to CC on bugs or contact about this fuzz target.
345 Cc []string `json:"cc,omitempty"`
hamzehe8a1bfa2022-06-21 12:22:06 -0700346 // A brief description of what the fuzzed code does.
347 Description string `json:"description,omitempty"`
hamzeheea256b2023-02-09 13:22:09 -0800348 // Whether the code being fuzzed is remotely accessible or requires privileges
349 // to access locally.
350 Vector Vector `json:"vector,omitempty"`
351 // How privileged the service being fuzzed is.
352 Service_privilege ServicePrivilege `json:"service_privilege,omitempty"`
353 // Whether the service being fuzzed handles data from multiple users or only
354 // a single one.
355 Users UserData `json:"users,omitempty"`
356 // Specifies the use state of the code being fuzzed. This state factors into
357 // how an issue is handled.
358 Fuzzed_code_usage FuzzedCodeUsage `json:"fuzzed_code_usage,omitempty"`
359 // Comment describing how we came to these settings for this fuzzer.
360 Config_comment string
361 // Which team to route this to, if it should be routed automatically.
362 Automatically_route_to AutomaticallyRouteTo `json:"automatically_route_to,omitempty"`
hamzehe8a1bfa2022-06-21 12:22:06 -0700363 // Can third party/untrusted apps supply data to fuzzed code.
hamzeh3c983d22022-07-26 14:19:22 -0700364 Untrusted_data *bool `json:"untrusted_data,omitempty"`
Jon Bottarinia0b44cb2022-10-19 03:13:14 +0000365 // When code was released or will be released.
hamzehe8a1bfa2022-06-21 12:22:06 -0700366 Production_date string `json:"production_date,omitempty"`
367 // Prevents critical service functionality like phone calls, bluetooth, etc.
hamzeh3c983d22022-07-26 14:19:22 -0700368 Critical *bool `json:"critical,omitempty"`
hamzehc0a671f2021-07-22 12:05:08 -0700369 // Specify whether to enable continuous fuzzing on devices. Defaults to true.
370 Fuzz_on_haiku_device *bool `json:"fuzz_on_haiku_device,omitempty"`
371 // Specify whether to enable continuous fuzzing on host. Defaults to true.
372 Fuzz_on_haiku_host *bool `json:"fuzz_on_haiku_host,omitempty"`
373 // Component in Google's bug tracking system that bugs should be filed to.
374 Componentid *int64 `json:"componentid,omitempty"`
Jon Bottarinia0b44cb2022-10-19 03:13:14 +0000375 // Hotlist(s) in Google's bug tracking system that bugs should be marked with.
hamzehc0a671f2021-07-22 12:05:08 -0700376 Hotlists []string `json:"hotlists,omitempty"`
377 // Specify whether this fuzz target was submitted by a researcher. Defaults
378 // to false.
379 Researcher_submitted *bool `json:"researcher_submitted,omitempty"`
380 // Specify who should be acknowledged for CVEs in the Android Security
381 // Bulletin.
382 Acknowledgement []string `json:"acknowledgement,omitempty"`
383 // Additional options to be passed to libfuzzer when run in Haiku.
384 Libfuzzer_options []string `json:"libfuzzer_options,omitempty"`
385 // Additional options to be passed to HWASAN when running on-device in Haiku.
386 Hwasan_options []string `json:"hwasan_options,omitempty"`
387 // Additional options to be passed to HWASAN when running on host in Haiku.
388 Asan_options []string `json:"asan_options,omitempty"`
Muhammad Haseeb Ahmad7e744052022-03-25 22:50:53 +0000389 // If there's a Java fuzzer with JNI, a different version of Jazzer would
390 // need to be added to the fuzzer package than one without JNI
391 IsJni *bool `json:"is_jni,omitempty"`
Mark74c0ad22022-09-30 21:13:01 +0000392 // List of modules for monitoring coverage drops in directories (e.g. "libicu")
393 Target_modules []string `json:"target_modules,omitempty"`
David Fuaf4e33b2023-04-07 12:24:35 -0700394 // Specifies a bug assignee to replace default ISE assignment
David Fu44fc9a82023-04-26 20:25:30 +0000395 Triage_assignee string `json:"triage_assignee,omitempty"`
Markf736b922023-05-08 22:11:44 +0000396 // Specifies libs used to initialize ART (java only, 'use_none' for no initialization)
397 Use_platform_libs UsePlatformLibs `json:"use_platform_libs,omitempty"`
David Fu4ad9bba2023-06-28 21:49:31 +0000398 // Specifies whether fuzz target should check presubmitted code changes for crashes.
399 // Defaults to false.
400 Use_for_presubmit *bool `json:"use_for_presubmit,omitempty"`
Cory Barker24907572023-07-18 21:19:53 +0000401 // Specify which paths to exclude from fuzzing coverage reports
402 Exclude_paths_from_reports []string `json:"exclude_paths_from_reports,omitempty"`
hamzehc0a671f2021-07-22 12:05:08 -0700403}
404
Cory Barker9cfcf6d2022-07-22 17:22:02 +0000405type FuzzFrameworks struct {
406 Afl *bool
407 Libfuzzer *bool
408 Jazzer *bool
409}
410
hamzehc0a671f2021-07-22 12:05:08 -0700411type FuzzProperties struct {
412 // Optional list of seed files to be installed to the fuzz target's output
413 // directory.
414 Corpus []string `android:"path"`
Cole Faust65cb40a2024-10-21 15:41:42 -0700415
416 // Same as corpus, but adds dependencies on module references using the device's os variant
417 // and the common arch variant.
418 Device_common_corpus []string `android:"path_device_common"`
419
hamzehc0a671f2021-07-22 12:05:08 -0700420 // Optional list of data files to be installed to the fuzz target's output
421 // directory. Directory structure relative to the module is preserved.
422 Data []string `android:"path"`
Cole Faustc3489f42024-12-06 13:07:18 -0800423 // Same as data, but adds dependencies on modules using the device's os variant, and common
424 // architecture's variant. Can be useful to add device-built apps to the data of a host
425 // test.
426 Device_common_data []string `android:"path_device_common"`
427 // Same as data, but adds dependencies on modules using the device's os variant, and the
428 // device's first architecture's variant. Can be useful to add device-built apps to the data
429 // of a host test.
430 Device_first_data []string `android:"path_device_first"`
Colin Crossb3614422025-02-18 15:18:18 -0800431
432 // Same as data, but will add dependencies on modules using the host's os variation and
433 // the common arch variation. Useful for a device test that wants to depend on a host
434 // module, for example to include a custom Tradefed test runner.
435 Host_common_data []string `android:"path_host_common"`
436
hamzehc0a671f2021-07-22 12:05:08 -0700437 // Optional dictionary to be installed to the fuzz target's output directory.
438 Dictionary *string `android:"path"`
Cory Barker9cfcf6d2022-07-22 17:22:02 +0000439 // Define the fuzzing frameworks this fuzz target can be built for. If
440 // empty then the fuzz target will be available to be built for all fuzz
441 // frameworks available
442 Fuzzing_frameworks *FuzzFrameworks
hamzehc0a671f2021-07-22 12:05:08 -0700443 // Config for running the target on fuzzing infrastructure.
444 Fuzz_config *FuzzConfig
445}
446
hamzeh41ad8812021-07-07 14:00:07 -0700447type FuzzPackagedModule struct {
Colin Cross5c1d5fb2023-11-15 12:39:40 -0800448 FuzzProperties FuzzProperties
449 Dictionary android.Path
450 Corpus android.Paths
451 Config android.Path
452 Data android.Paths
hamzeh41ad8812021-07-07 14:00:07 -0700453}
454
Yu Liu119d38c2025-02-25 22:25:11 +0000455type FuzzConfigInfo struct {
456 Vector Vector
457 // How privileged the service being fuzzed is.
458 ServicePrivilege ServicePrivilege
459 // Whether the service being fuzzed handles data from multiple users or only
460 // a single one.
461 Users UserData
462 // Specifies the use state of the code being fuzzed. This state factors into
463 // how an issue is handled.
464 FuzzedCodeUsage FuzzedCodeUsage
465 // Which team to route this to, if it should be routed automatically.
466 AutomaticallyRouteTo AutomaticallyRouteTo
467 // Specifies libs used to initialize ART (java only, 'use_none' for no initialization)
468 UsePlatformLibs UsePlatformLibs
469 // Specify whether to enable continuous fuzzing on devices. Defaults to true.
470 FuzzOnHaikuDevice bool
471 // Specify whether to enable continuous fuzzing on host. Defaults to true.
472 FuzzOnHaikuHost bool
473 // Specifies whether fuzz target should check presubmitted code changes for crashes.
474 // Defaults to false.
475 UseForPresubmit bool
476}
477type FuzzPackagedModuleInfo struct {
478 FuzzConfig *FuzzConfigInfo
479 Dictionary android.Path
480 Corpus android.Paths
481 Config android.Path
482 Data android.Paths
483}
484
485var FuzzPackagedModuleInfoProvider = blueprint.NewProvider[FuzzPackagedModuleInfo]()
486
487func SetFuzzPackagedModuleInfo(ctx android.ModuleContext, fm *FuzzPackagedModule) {
488 info := FuzzPackagedModuleInfo{
489 Dictionary: fm.Dictionary,
490 Config: fm.Config,
491 Corpus: fm.Corpus,
492 Data: fm.Data,
493 }
494 if fm.FuzzProperties.Fuzz_config != nil {
495 info.FuzzConfig = &FuzzConfigInfo{
496 Vector: fm.FuzzProperties.Fuzz_config.Vector,
497 ServicePrivilege: fm.FuzzProperties.Fuzz_config.Service_privilege,
498 Users: fm.FuzzProperties.Fuzz_config.Users,
499 FuzzedCodeUsage: fm.FuzzProperties.Fuzz_config.Fuzzed_code_usage,
500 AutomaticallyRouteTo: fm.FuzzProperties.Fuzz_config.Automatically_route_to,
501 FuzzOnHaikuDevice: BoolDefault(fm.FuzzProperties.Fuzz_config.Fuzz_on_haiku_device, true),
502 FuzzOnHaikuHost: BoolDefault(fm.FuzzProperties.Fuzz_config.Fuzz_on_haiku_host, true),
503 UsePlatformLibs: fm.FuzzProperties.Fuzz_config.Use_platform_libs,
504 UseForPresubmit: BoolDefault(fm.FuzzProperties.Fuzz_config.Use_for_presubmit, false),
505 }
506 }
507
508 android.SetProvider(ctx, FuzzPackagedModuleInfoProvider, info)
509}
510
Cory Barker9cfcf6d2022-07-22 17:22:02 +0000511func GetFramework(ctx android.LoadHookContext, lang Lang) Framework {
512 framework := ctx.Config().Getenv("FUZZ_FRAMEWORK")
513
514 if lang == Cc {
515 switch strings.ToLower(framework) {
516 case "":
517 return LibFuzzer
518 case "libfuzzer":
519 return LibFuzzer
520 case "afl":
521 return AFL
522 }
523 } else if lang == Rust {
524 return LibFuzzer
525 } else if lang == Java {
526 return Jazzer
527 }
528
529 ctx.ModuleErrorf(fmt.Sprintf("%s is not a valid fuzzing framework for %s", framework, lang))
530 return UnknownFramework
531}
532
533func IsValidFrameworkForModule(targetFramework Framework, lang Lang, moduleFrameworks *FuzzFrameworks) bool {
534 if targetFramework == UnknownFramework {
535 return false
536 }
537
538 if moduleFrameworks == nil {
539 return true
540 }
541
542 switch targetFramework {
543 case LibFuzzer:
544 return proptools.BoolDefault(moduleFrameworks.Libfuzzer, true)
545 case AFL:
546 return proptools.BoolDefault(moduleFrameworks.Afl, true)
547 case Jazzer:
548 return proptools.BoolDefault(moduleFrameworks.Jazzer, true)
549 default:
550 panic("%s is not supported as a fuzz framework")
551 }
552}
553
Cole Fauste8a87832024-09-11 11:35:46 -0700554func IsValid(ctx android.ConfigurableEvaluatorContext, fuzzModule FuzzModule) bool {
hamzeh41ad8812021-07-07 14:00:07 -0700555 // Discard ramdisk + vendor_ramdisk + recovery modules, they're duplicates of
556 // fuzz targets we're going to package anyway.
Cole Fausta963b942024-04-11 17:43:00 -0700557 if !fuzzModule.Enabled(ctx) || fuzzModule.InRamdisk() || fuzzModule.InVendorRamdisk() || fuzzModule.InRecovery() {
hamzeh41ad8812021-07-07 14:00:07 -0700558 return false
559 }
560
561 // Discard modules that are in an unavailable namespace.
562 if !fuzzModule.ExportedToMake() {
563 return false
564 }
565
566 return true
567}
568
Yu Liu119d38c2025-02-25 22:25:11 +0000569// TODO(b/397766191): Change the signature to take ModuleProxy
570// Please only access the module's internal data through providers.
571func (s *FuzzPackager) PackageArtifacts(ctx android.SingletonContext, module android.Module, fuzzModule *FuzzPackagedModuleInfo, archDir android.OutputPath, builder *android.RuleBuilder) []FileToZip {
hamzeh41ad8812021-07-07 14:00:07 -0700572 // Package the corpora into a zipfile.
573 var files []FileToZip
574 if fuzzModule.Corpus != nil {
575 corpusZip := archDir.Join(ctx, module.Name()+"_seed_corpus.zip")
576 command := builder.Command().BuiltTool("soong_zip").
577 Flag("-j").
578 FlagWithOutput("-o ", corpusZip)
579 rspFile := corpusZip.ReplaceExtension(ctx, "rsp")
580 command.FlagWithRspFileInputList("-r ", rspFile, fuzzModule.Corpus)
Colin Cross80462dc2023-05-08 15:09:31 -0700581 files = append(files, FileToZip{SourceFilePath: corpusZip})
hamzeh41ad8812021-07-07 14:00:07 -0700582 }
583
584 // Package the data into a zipfile.
585 if fuzzModule.Data != nil {
586 dataZip := archDir.Join(ctx, module.Name()+"_data.zip")
587 command := builder.Command().BuiltTool("soong_zip").
588 FlagWithOutput("-o ", dataZip)
589 for _, f := range fuzzModule.Data {
590 intermediateDir := strings.TrimSuffix(f.String(), f.Rel())
591 command.FlagWithArg("-C ", intermediateDir)
592 command.FlagWithInput("-f ", f)
593 }
Colin Cross80462dc2023-05-08 15:09:31 -0700594 files = append(files, FileToZip{SourceFilePath: dataZip})
hamzeh41ad8812021-07-07 14:00:07 -0700595 }
596
597 // The dictionary.
598 if fuzzModule.Dictionary != nil {
Colin Cross80462dc2023-05-08 15:09:31 -0700599 files = append(files, FileToZip{SourceFilePath: fuzzModule.Dictionary})
hamzeh41ad8812021-07-07 14:00:07 -0700600 }
601
602 // Additional fuzz config.
hamzehe8a1bfa2022-06-21 12:22:06 -0700603 if fuzzModule.Config != nil && IsValidConfig(fuzzModule, module.Name()) {
Colin Cross80462dc2023-05-08 15:09:31 -0700604 files = append(files, FileToZip{SourceFilePath: fuzzModule.Config})
hamzeh41ad8812021-07-07 14:00:07 -0700605 }
606
607 return files
608}
609
Yu Liu119d38c2025-02-25 22:25:11 +0000610// TODO(b/397766191): Change the signature to take ModuleProxy
611// Please only access the module's internal data through providers.
612func (s *FuzzPackager) BuildZipFile(ctx android.SingletonContext, module android.Module, fuzzModule *FuzzPackagedModuleInfo, files []FileToZip, builder *android.RuleBuilder, archDir android.OutputPath, archString string, hostOrTargetString string, archOs ArchOs, archDirs map[ArchOs][]FileToZip) ([]FileToZip, bool) {
hamzeh41ad8812021-07-07 14:00:07 -0700613 fuzzZip := archDir.Join(ctx, module.Name()+".zip")
614
615 command := builder.Command().BuiltTool("soong_zip").
616 Flag("-j").
617 FlagWithOutput("-o ", fuzzZip)
618
619 for _, file := range files {
620 if file.DestinationPathPrefix != "" {
621 command.FlagWithArg("-P ", file.DestinationPathPrefix)
622 } else {
623 command.Flag("-P ''")
624 }
Colin Cross80462dc2023-05-08 15:09:31 -0700625 if file.DestinationPath != "" {
626 command.FlagWithArg("-e ", file.DestinationPath)
627 }
hamzeh41ad8812021-07-07 14:00:07 -0700628 command.FlagWithInput("-f ", file.SourceFilePath)
629 }
630
631 builder.Build("create-"+fuzzZip.String(),
632 "Package "+module.Name()+" for "+archString+"-"+hostOrTargetString)
633
Yu Liu119d38c2025-02-25 22:25:11 +0000634 if config := fuzzModule.FuzzConfig; config != nil {
635 if strings.Contains(hostOrTargetString, "host") && !config.FuzzOnHaikuHost {
hamzeh41ad8812021-07-07 14:00:07 -0700636 return archDirs[archOs], false
Yu Liu119d38c2025-02-25 22:25:11 +0000637 } else if !strings.Contains(hostOrTargetString, "host") && !config.FuzzOnHaikuDevice {
hamzeh41ad8812021-07-07 14:00:07 -0700638 return archDirs[archOs], false
639 }
640 }
641
642 s.FuzzTargets[module.Name()] = true
Colin Cross80462dc2023-05-08 15:09:31 -0700643 archDirs[archOs] = append(archDirs[archOs], FileToZip{SourceFilePath: fuzzZip})
hamzeh41ad8812021-07-07 14:00:07 -0700644
645 return archDirs[archOs], true
646}
647
hamzehc0a671f2021-07-22 12:05:08 -0700648func (f *FuzzConfig) String() string {
649 b, err := json.Marshal(f)
650 if err != nil {
651 panic(err)
652 }
653
654 return string(b)
655}
656
Cory Barker9cfcf6d2022-07-22 17:22:02 +0000657func (s *FuzzPackager) CreateFuzzPackage(ctx android.SingletonContext, archDirs map[ArchOs][]FileToZip, fuzzType Lang, pctx android.PackageContext) {
hamzeh41ad8812021-07-07 14:00:07 -0700658 var archOsList []ArchOs
659 for archOs := range archDirs {
660 archOsList = append(archOsList, archOs)
661 }
662 sort.Slice(archOsList, func(i, j int) bool { return archOsList[i].Dir < archOsList[j].Dir })
663
664 for _, archOs := range archOsList {
665 filesToZip := archDirs[archOs]
666 arch := archOs.Arch
667 hostOrTarget := archOs.HostOrTarget
668 builder := android.NewRuleBuilder(pctx, ctx)
669 zipFileName := "fuzz-" + hostOrTarget + "-" + arch + ".zip"
Cory Barkera1da26f2022-06-07 20:12:06 +0000670 if fuzzType == Rust {
hamzeh41ad8812021-07-07 14:00:07 -0700671 zipFileName = "fuzz-rust-" + hostOrTarget + "-" + arch + ".zip"
672 }
Cory Barkera1da26f2022-06-07 20:12:06 +0000673 if fuzzType == Java {
Muhammad Haseeb Ahmade3803102022-01-10 21:37:07 +0000674 zipFileName = "fuzz-java-" + hostOrTarget + "-" + arch + ".zip"
675 }
Cory Barker9cfcf6d2022-07-22 17:22:02 +0000676
hamzeh41ad8812021-07-07 14:00:07 -0700677 outputFile := android.PathForOutput(ctx, zipFileName)
678
679 s.Packages = append(s.Packages, outputFile)
680
681 command := builder.Command().BuiltTool("soong_zip").
682 Flag("-j").
683 FlagWithOutput("-o ", outputFile).
684 Flag("-L 0") // No need to try and re-compress the zipfiles.
685
686 for _, fileToZip := range filesToZip {
hamzeh41ad8812021-07-07 14:00:07 -0700687 if fileToZip.DestinationPathPrefix != "" {
688 command.FlagWithArg("-P ", fileToZip.DestinationPathPrefix)
689 } else {
690 command.Flag("-P ''")
691 }
692 command.FlagWithInput("-f ", fileToZip.SourceFilePath)
693
694 }
695 builder.Build("create-fuzz-package-"+arch+"-"+hostOrTarget,
696 "Create fuzz target packages for "+arch+"-"+hostOrTarget)
697 }
698}
699
700func (s *FuzzPackager) PreallocateSlice(ctx android.MakeVarsContext, targets string) {
701 fuzzTargets := make([]string, 0, len(s.FuzzTargets))
702 for target, _ := range s.FuzzTargets {
703 fuzzTargets = append(fuzzTargets, target)
704 }
Cory Barkera1da26f2022-06-07 20:12:06 +0000705
hamzeh41ad8812021-07-07 14:00:07 -0700706 sort.Strings(fuzzTargets)
707 ctx.Strict(targets, strings.Join(fuzzTargets, " "))
708}