| hamzeh | 41ad881 | 2021-07-07 14:00:07 -0700 | [diff] [blame] | 1 | // 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 |  | 
| hamzeh | c0a671f | 2021-07-22 12:05:08 -0700 | [diff] [blame] | 15 | package fuzz | 
| hamzeh | 41ad881 | 2021-07-07 14:00:07 -0700 | [diff] [blame] | 16 |  | 
|  | 17 | // This file contains the common code for compiling C/C++ and Rust fuzzers for Android. | 
|  | 18 |  | 
|  | 19 | import ( | 
| hamzeh | c0a671f | 2021-07-22 12:05:08 -0700 | [diff] [blame] | 20 | "encoding/json" | 
| hamzeh | e8a1bfa | 2022-06-21 12:22:06 -0700 | [diff] [blame] | 21 | "fmt" | 
| hamzeh | 41ad881 | 2021-07-07 14:00:07 -0700 | [diff] [blame] | 22 | "sort" | 
|  | 23 | "strings" | 
|  | 24 |  | 
| hamzeh | c0a671f | 2021-07-22 12:05:08 -0700 | [diff] [blame] | 25 | "github.com/google/blueprint/proptools" | 
|  | 26 |  | 
| hamzeh | 41ad881 | 2021-07-07 14:00:07 -0700 | [diff] [blame] | 27 | "android/soong/android" | 
|  | 28 | ) | 
|  | 29 |  | 
| Cory Barker | 9cfcf6d | 2022-07-22 17:22:02 +0000 | [diff] [blame] | 30 | type Lang string | 
| hamzeh | 41ad881 | 2021-07-07 14:00:07 -0700 | [diff] [blame] | 31 |  | 
|  | 32 | const ( | 
| Cory Barker | 9cfcf6d | 2022-07-22 17:22:02 +0000 | [diff] [blame] | 33 | Cc   Lang = "cc" | 
|  | 34 | Rust Lang = "rust" | 
|  | 35 | Java Lang = "java" | 
|  | 36 | ) | 
|  | 37 |  | 
|  | 38 | type Framework string | 
|  | 39 |  | 
|  | 40 | const ( | 
|  | 41 | AFL              Framework = "afl" | 
|  | 42 | LibFuzzer        Framework = "libfuzzer" | 
|  | 43 | Jazzer           Framework = "jazzer" | 
|  | 44 | UnknownFramework Framework = "unknownframework" | 
| hamzeh | 41ad881 | 2021-07-07 14:00:07 -0700 | [diff] [blame] | 45 | ) | 
|  | 46 |  | 
| hamzeh | c0a671f | 2021-07-22 12:05:08 -0700 | [diff] [blame] | 47 | var BoolDefault = proptools.BoolDefault | 
|  | 48 |  | 
| hamzeh | 41ad881 | 2021-07-07 14:00:07 -0700 | [diff] [blame] | 49 | type FuzzModule struct { | 
|  | 50 | android.ModuleBase | 
|  | 51 | android.DefaultableModuleBase | 
|  | 52 | android.ApexModuleBase | 
|  | 53 | } | 
|  | 54 |  | 
|  | 55 | type FuzzPackager struct { | 
| Ivan Lozano | 39b0bf0 | 2021-10-14 12:22:09 -0400 | [diff] [blame] | 56 | Packages                android.Paths | 
|  | 57 | FuzzTargets             map[string]bool | 
|  | 58 | SharedLibInstallStrings []string | 
| hamzeh | 41ad881 | 2021-07-07 14:00:07 -0700 | [diff] [blame] | 59 | } | 
|  | 60 |  | 
|  | 61 | type FileToZip struct { | 
|  | 62 | SourceFilePath        android.Path | 
|  | 63 | DestinationPathPrefix string | 
| Colin Cross | 80462dc | 2023-05-08 15:09:31 -0700 | [diff] [blame] | 64 | DestinationPath       string | 
| hamzeh | 41ad881 | 2021-07-07 14:00:07 -0700 | [diff] [blame] | 65 | } | 
|  | 66 |  | 
|  | 67 | type ArchOs struct { | 
|  | 68 | HostOrTarget string | 
|  | 69 | Arch         string | 
|  | 70 | Dir          string | 
|  | 71 | } | 
|  | 72 |  | 
| hamzeh | eea256b | 2023-02-09 13:22:09 -0800 | [diff] [blame] | 73 | type Vector string | 
| hamzeh | e8a1bfa | 2022-06-21 12:22:06 -0700 | [diff] [blame] | 74 |  | 
|  | 75 | const ( | 
| hamzeh | eea256b | 2023-02-09 13:22:09 -0800 | [diff] [blame] | 76 | unknown_access_vector Vector = "unknown_access_vector" | 
|  | 77 | // The code being fuzzed is reachable from a remote source, or using data | 
|  | 78 | // provided by a remote source.  For example: media codecs process media files | 
|  | 79 | // from the internet, SMS processing handles remote message data. | 
|  | 80 | // See | 
|  | 81 | // https://source.android.com/docs/security/overview/updates-resources#local-vs-remote | 
|  | 82 | // for an explanation of what's considered "remote." | 
|  | 83 | remote = "remote" | 
|  | 84 | // The code being fuzzed can only be reached locally, such as from an | 
|  | 85 | // installed app.  As an example, if it's fuzzing a Binder interface, it's | 
|  | 86 | // assumed that you'd need a local app to make arbitrary Binder calls. | 
|  | 87 | // And the app that's calling the fuzzed code does not require any privileges; | 
|  | 88 | // any 3rd party app could make these calls. | 
|  | 89 | local_no_privileges_required = "local_no_privileges_required" | 
|  | 90 | // The code being fuzzed can only be called locally, and the calling process | 
|  | 91 | // requires additional permissions that prevent arbitrary 3rd party apps from | 
|  | 92 | // calling the code.  For instance: this requires a privileged or signature | 
|  | 93 | // permission to reach, or SELinux restrictions prevent the untrusted_app | 
|  | 94 | // domain from calling it. | 
|  | 95 | local_privileges_required = "local_privileges_required" | 
|  | 96 | // The code is only callable on a PC host, not on a production Android device. | 
|  | 97 | // For instance, this is fuzzing code used during the build process, or | 
|  | 98 | // tooling that does not exist on a user's actual Android device. | 
|  | 99 | host_access = "host_access" | 
|  | 100 | // The code being fuzzed is only reachable if the user has enabled Developer | 
|  | 101 | // Options, or has enabled a persistent Developer Options setting. | 
|  | 102 | local_with_developer_options = "local_with_developer_options" | 
| hamzeh | e8a1bfa | 2022-06-21 12:22:06 -0700 | [diff] [blame] | 103 | ) | 
|  | 104 |  | 
| hamzeh | eea256b | 2023-02-09 13:22:09 -0800 | [diff] [blame] | 105 | func (vector Vector) isValidVector() bool { | 
|  | 106 | switch vector { | 
|  | 107 | case "", | 
|  | 108 | unknown_access_vector, | 
|  | 109 | remote, | 
|  | 110 | local_no_privileges_required, | 
|  | 111 | local_privileges_required, | 
|  | 112 | host_access, | 
|  | 113 | local_with_developer_options: | 
|  | 114 | return true | 
|  | 115 | } | 
|  | 116 | return false | 
|  | 117 | } | 
|  | 118 |  | 
|  | 119 | type ServicePrivilege string | 
|  | 120 |  | 
|  | 121 | const ( | 
|  | 122 | unknown_service_privilege ServicePrivilege = "unknown_service_privilege" | 
|  | 123 | // The code being fuzzed runs on a Secure Element.  This has access to some | 
|  | 124 | // of the most privileged data on the device, such as authentication keys. | 
|  | 125 | // Not all devices have a Secure Element. | 
|  | 126 | secure_element = "secure_element" | 
|  | 127 | // The code being fuzzed runs in the TEE.  The TEE is designed to be resistant | 
|  | 128 | // to a compromised kernel, and stores sensitive data. | 
|  | 129 | trusted_execution = "trusted_execution" | 
|  | 130 | // The code being fuzzed has privileges beyond what arbitrary 3rd party apps | 
|  | 131 | // have.  For instance, it's running as the System UID, or it's in an SELinux | 
|  | 132 | // domain that's able to perform calls that can't be made by 3rd party apps. | 
|  | 133 | privileged = "privileged" | 
|  | 134 | // The code being fuzzed is equivalent to a 3rd party app.  It runs in the | 
|  | 135 | // untrusted_app SELinux domain, or it only has privileges that are equivalent | 
|  | 136 | // to what a 3rd party app could have. | 
|  | 137 | unprivileged = "unprivileged" | 
|  | 138 | // The code being fuzzed is significantly constrained, and even if it's | 
|  | 139 | // compromised, it has significant restrictions that prevent it from | 
|  | 140 | // performing most actions.  This is significantly more restricted than | 
|  | 141 | // UNPRIVILEGED.  An example is the isolatedProcess=true setting in a 3rd | 
|  | 142 | // party app.  Or a process that's very restricted by SELinux, such as | 
|  | 143 | // anything in the mediacodec SELinux domain. | 
|  | 144 | constrained = "constrained" | 
|  | 145 | // The code being fuzzed always has Negligible Security Impact.  Even | 
|  | 146 | // arbitrary out of bounds writes and full code execution would not be | 
|  | 147 | // considered a security vulnerability.  This typically only makes sense if | 
|  | 148 | // FuzzedCodeUsage is set to FUTURE_VERSION or EXPERIMENTAL, and if | 
|  | 149 | // AutomaticallyRouteTo is set to ALWAYS_NSI. | 
|  | 150 | nsi = "nsi" | 
|  | 151 | // The code being fuzzed only runs on a PC host, not on a production Android | 
|  | 152 | // device.  For instance, the fuzzer is fuzzing code used during the build | 
|  | 153 | // process, or tooling that does not exist on a user's actual Android device. | 
|  | 154 | host_only = "host_only" | 
|  | 155 | ) | 
|  | 156 |  | 
|  | 157 | func (service_privilege ServicePrivilege) isValidServicePrivilege() bool { | 
|  | 158 | switch service_privilege { | 
|  | 159 | case "", | 
|  | 160 | unknown_service_privilege, | 
|  | 161 | secure_element, | 
|  | 162 | trusted_execution, | 
|  | 163 | privileged, | 
|  | 164 | unprivileged, | 
|  | 165 | constrained, | 
|  | 166 | nsi, | 
|  | 167 | host_only: | 
|  | 168 | return true | 
|  | 169 | } | 
|  | 170 | return false | 
|  | 171 | } | 
|  | 172 |  | 
| Mark | f736b92 | 2023-05-08 22:11:44 +0000 | [diff] [blame] | 173 | type UsePlatformLibs string | 
|  | 174 |  | 
|  | 175 | const ( | 
|  | 176 | unknown_use_platform_libs UsePlatformLibs = "unknown_use_platform_libs" | 
|  | 177 | // Use the native libraries on the device, typically in /system directory | 
|  | 178 | use_platform_libs = "use_platform_libs" | 
|  | 179 | // Do not use any native libraries (ART will not be initialized) | 
|  | 180 | use_none = "use_none" | 
|  | 181 | ) | 
|  | 182 |  | 
|  | 183 | func (use_platform_libs UsePlatformLibs) isValidUsePlatformLibs() bool { | 
|  | 184 | switch use_platform_libs { | 
|  | 185 | case "", | 
|  | 186 | unknown_use_platform_libs, | 
|  | 187 | use_platform_libs, | 
|  | 188 | use_none: | 
|  | 189 | return true | 
|  | 190 | } | 
|  | 191 | return false | 
|  | 192 | } | 
|  | 193 |  | 
| hamzeh | eea256b | 2023-02-09 13:22:09 -0800 | [diff] [blame] | 194 | type UserData string | 
|  | 195 |  | 
|  | 196 | const ( | 
|  | 197 | unknown_user_data UserData = "unknown_user_data" | 
|  | 198 | // The process being fuzzed only handles data from a single user, or from a | 
|  | 199 | // single process or app.  It's possible the process shuts down before | 
|  | 200 | // handling data from another user/process/app, or it's possible the process | 
|  | 201 | // only ever handles one user's/process's/app's data.  As an example, some | 
|  | 202 | // print spooler processes are started for a single document and terminate | 
|  | 203 | // when done, so each instance only handles data from a single user/app. | 
|  | 204 | single_user = "single_user" | 
|  | 205 | // The process handles data from multiple users, or from multiple other apps | 
|  | 206 | // or processes.  Media processes, for instance, can handle media requests | 
|  | 207 | // from multiple different apps without restarting.  Wi-Fi and network | 
|  | 208 | // processes handle data from multiple users, and processes, and apps. | 
|  | 209 | multi_user = "multi_user" | 
|  | 210 | ) | 
|  | 211 |  | 
|  | 212 | func (user_data UserData) isValidUserData() bool { | 
|  | 213 | switch user_data { | 
|  | 214 | case "", | 
|  | 215 | unknown_user_data, | 
|  | 216 | single_user, | 
|  | 217 | multi_user: | 
|  | 218 | return true | 
|  | 219 | } | 
|  | 220 | return false | 
|  | 221 | } | 
|  | 222 |  | 
|  | 223 | type FuzzedCodeUsage string | 
|  | 224 |  | 
|  | 225 | const ( | 
|  | 226 | undefined FuzzedCodeUsage = "undefined" | 
|  | 227 | unknown                   = "unknown" | 
|  | 228 | // The code being fuzzed exists in a shipped version of Android and runs on | 
|  | 229 | // devices in production. | 
|  | 230 | shipped = "shipped" | 
|  | 231 | // The code being fuzzed is not yet in a shipping version of Android, but it | 
|  | 232 | // will be at some point in the future. | 
|  | 233 | future_version = "future_version" | 
|  | 234 | // The code being fuzzed is not in a shipping version of Android, and there | 
|  | 235 | // are no plans to ship it in the future. | 
|  | 236 | experimental = "experimental" | 
|  | 237 | ) | 
|  | 238 |  | 
|  | 239 | func (fuzzed_code_usage FuzzedCodeUsage) isValidFuzzedCodeUsage() bool { | 
|  | 240 | switch fuzzed_code_usage { | 
|  | 241 | case "", | 
|  | 242 | undefined, | 
|  | 243 | unknown, | 
|  | 244 | shipped, | 
|  | 245 | future_version, | 
|  | 246 | experimental: | 
|  | 247 | return true | 
|  | 248 | } | 
|  | 249 | return false | 
|  | 250 | } | 
|  | 251 |  | 
|  | 252 | type AutomaticallyRouteTo string | 
|  | 253 |  | 
|  | 254 | const ( | 
|  | 255 | undefined_routing AutomaticallyRouteTo = "undefined_routing" | 
|  | 256 | // Automatically route this to the Android Automotive security team for | 
|  | 257 | // assessment. | 
|  | 258 | android_automotive = "android_automotive" | 
|  | 259 | // This should not be used in fuzzer configurations.  It is used internally | 
|  | 260 | // by Severity Assigner to flag memory leak reports. | 
|  | 261 | memory_leak = "memory_leak" | 
|  | 262 | // Route this vulnerability to our Ittiam vendor team for assessment. | 
|  | 263 | ittiam = "ittiam" | 
|  | 264 | // Reports from this fuzzer are always NSI (see the NSI ServicePrivilegeEnum | 
|  | 265 | // value for additional context).  It is not possible for this code to ever | 
|  | 266 | // have a security vulnerability. | 
|  | 267 | always_nsi = "always_nsi" | 
|  | 268 | // Route this vulnerability to AIDL team for assessment. | 
|  | 269 | aidl = "aidl" | 
|  | 270 | ) | 
|  | 271 |  | 
|  | 272 | func (automatically_route_to AutomaticallyRouteTo) isValidAutomaticallyRouteTo() bool { | 
|  | 273 | switch automatically_route_to { | 
|  | 274 | case "", | 
|  | 275 | undefined_routing, | 
|  | 276 | android_automotive, | 
|  | 277 | memory_leak, | 
|  | 278 | ittiam, | 
|  | 279 | always_nsi, | 
|  | 280 | aidl: | 
|  | 281 | return true | 
|  | 282 | } | 
|  | 283 | return false | 
|  | 284 | } | 
|  | 285 |  | 
| hamzeh | e8a1bfa | 2022-06-21 12:22:06 -0700 | [diff] [blame] | 286 | func IsValidConfig(fuzzModule FuzzPackagedModule, moduleName string) bool { | 
|  | 287 | var config = fuzzModule.FuzzProperties.Fuzz_config | 
|  | 288 | if config != nil { | 
| hamzeh | eea256b | 2023-02-09 13:22:09 -0800 | [diff] [blame] | 289 | if !config.Vector.isValidVector() { | 
|  | 290 | panic(fmt.Errorf("Invalid vector in fuzz config in %s", moduleName)) | 
| hamzeh | e8a1bfa | 2022-06-21 12:22:06 -0700 | [diff] [blame] | 291 | } | 
| hamzeh | eea256b | 2023-02-09 13:22:09 -0800 | [diff] [blame] | 292 |  | 
|  | 293 | if !config.Service_privilege.isValidServicePrivilege() { | 
|  | 294 | panic(fmt.Errorf("Invalid service_privilege in fuzz config in %s", moduleName)) | 
|  | 295 | } | 
|  | 296 |  | 
|  | 297 | if !config.Users.isValidUserData() { | 
|  | 298 | panic(fmt.Errorf("Invalid users (user_data) in fuzz config in %s", moduleName)) | 
|  | 299 | } | 
|  | 300 |  | 
|  | 301 | if !config.Fuzzed_code_usage.isValidFuzzedCodeUsage() { | 
|  | 302 | panic(fmt.Errorf("Invalid fuzzed_code_usage in fuzz config in %s", moduleName)) | 
|  | 303 | } | 
|  | 304 |  | 
|  | 305 | if !config.Automatically_route_to.isValidAutomaticallyRouteTo() { | 
|  | 306 | panic(fmt.Errorf("Invalid automatically_route_to in fuzz config in %s", moduleName)) | 
|  | 307 | } | 
| Mark | f736b92 | 2023-05-08 22:11:44 +0000 | [diff] [blame] | 308 |  | 
|  | 309 | if !config.Use_platform_libs.isValidUsePlatformLibs() { | 
|  | 310 | panic(fmt.Errorf("Invalid use_platform_libs in fuzz config in %s", moduleName)) | 
|  | 311 | } | 
| hamzeh | e8a1bfa | 2022-06-21 12:22:06 -0700 | [diff] [blame] | 312 | } | 
| hamzeh | eea256b | 2023-02-09 13:22:09 -0800 | [diff] [blame] | 313 | return true | 
| hamzeh | e8a1bfa | 2022-06-21 12:22:06 -0700 | [diff] [blame] | 314 | } | 
|  | 315 |  | 
| hamzeh | c0a671f | 2021-07-22 12:05:08 -0700 | [diff] [blame] | 316 | type FuzzConfig struct { | 
|  | 317 | // Email address of people to CC on bugs or contact about this fuzz target. | 
|  | 318 | Cc []string `json:"cc,omitempty"` | 
| hamzeh | e8a1bfa | 2022-06-21 12:22:06 -0700 | [diff] [blame] | 319 | // A brief description of what the fuzzed code does. | 
|  | 320 | Description string `json:"description,omitempty"` | 
| hamzeh | eea256b | 2023-02-09 13:22:09 -0800 | [diff] [blame] | 321 | // Whether the code being fuzzed is remotely accessible or requires privileges | 
|  | 322 | // to access locally. | 
|  | 323 | Vector Vector `json:"vector,omitempty"` | 
|  | 324 | // How privileged the service being fuzzed is. | 
|  | 325 | Service_privilege ServicePrivilege `json:"service_privilege,omitempty"` | 
|  | 326 | // Whether the service being fuzzed handles data from multiple users or only | 
|  | 327 | // a single one. | 
|  | 328 | Users UserData `json:"users,omitempty"` | 
|  | 329 | // Specifies the use state of the code being fuzzed. This state factors into | 
|  | 330 | // how an issue is handled. | 
|  | 331 | Fuzzed_code_usage FuzzedCodeUsage `json:"fuzzed_code_usage,omitempty"` | 
|  | 332 | // Comment describing how we came to these settings for this fuzzer. | 
|  | 333 | Config_comment string | 
|  | 334 | // Which team to route this to, if it should be routed automatically. | 
|  | 335 | Automatically_route_to AutomaticallyRouteTo `json:"automatically_route_to,omitempty"` | 
| hamzeh | e8a1bfa | 2022-06-21 12:22:06 -0700 | [diff] [blame] | 336 | // Can third party/untrusted apps supply data to fuzzed code. | 
| hamzeh | 3c983d2 | 2022-07-26 14:19:22 -0700 | [diff] [blame] | 337 | Untrusted_data *bool `json:"untrusted_data,omitempty"` | 
| Jon Bottarini | a0b44cb | 2022-10-19 03:13:14 +0000 | [diff] [blame] | 338 | // When code was released or will be released. | 
| hamzeh | e8a1bfa | 2022-06-21 12:22:06 -0700 | [diff] [blame] | 339 | Production_date string `json:"production_date,omitempty"` | 
|  | 340 | // Prevents critical service functionality like phone calls, bluetooth, etc. | 
| hamzeh | 3c983d2 | 2022-07-26 14:19:22 -0700 | [diff] [blame] | 341 | Critical *bool `json:"critical,omitempty"` | 
| hamzeh | c0a671f | 2021-07-22 12:05:08 -0700 | [diff] [blame] | 342 | // Specify whether to enable continuous fuzzing on devices. Defaults to true. | 
|  | 343 | Fuzz_on_haiku_device *bool `json:"fuzz_on_haiku_device,omitempty"` | 
|  | 344 | // Specify whether to enable continuous fuzzing on host. Defaults to true. | 
|  | 345 | Fuzz_on_haiku_host *bool `json:"fuzz_on_haiku_host,omitempty"` | 
|  | 346 | // Component in Google's bug tracking system that bugs should be filed to. | 
|  | 347 | Componentid *int64 `json:"componentid,omitempty"` | 
| Jon Bottarini | a0b44cb | 2022-10-19 03:13:14 +0000 | [diff] [blame] | 348 | // Hotlist(s) in Google's bug tracking system that bugs should be marked with. | 
| hamzeh | c0a671f | 2021-07-22 12:05:08 -0700 | [diff] [blame] | 349 | Hotlists []string `json:"hotlists,omitempty"` | 
|  | 350 | // Specify whether this fuzz target was submitted by a researcher. Defaults | 
|  | 351 | // to false. | 
|  | 352 | Researcher_submitted *bool `json:"researcher_submitted,omitempty"` | 
|  | 353 | // Specify who should be acknowledged for CVEs in the Android Security | 
|  | 354 | // Bulletin. | 
|  | 355 | Acknowledgement []string `json:"acknowledgement,omitempty"` | 
|  | 356 | // Additional options to be passed to libfuzzer when run in Haiku. | 
|  | 357 | Libfuzzer_options []string `json:"libfuzzer_options,omitempty"` | 
|  | 358 | // Additional options to be passed to HWASAN when running on-device in Haiku. | 
|  | 359 | Hwasan_options []string `json:"hwasan_options,omitempty"` | 
|  | 360 | // Additional options to be passed to HWASAN when running on host in Haiku. | 
|  | 361 | Asan_options []string `json:"asan_options,omitempty"` | 
| Muhammad Haseeb Ahmad | 7e74405 | 2022-03-25 22:50:53 +0000 | [diff] [blame] | 362 | // If there's a Java fuzzer with JNI, a different version of Jazzer would | 
|  | 363 | // need to be added to the fuzzer package than one without JNI | 
|  | 364 | IsJni *bool `json:"is_jni,omitempty"` | 
| Mark | 74c0ad2 | 2022-09-30 21:13:01 +0000 | [diff] [blame] | 365 | // List of modules for monitoring coverage drops in directories (e.g. "libicu") | 
|  | 366 | Target_modules []string `json:"target_modules,omitempty"` | 
| David Fu | af4e33b | 2023-04-07 12:24:35 -0700 | [diff] [blame] | 367 | // Specifies a bug assignee to replace default ISE assignment | 
| David Fu | 44fc9a8 | 2023-04-26 20:25:30 +0000 | [diff] [blame] | 368 | Triage_assignee string `json:"triage_assignee,omitempty"` | 
| Mark | f736b92 | 2023-05-08 22:11:44 +0000 | [diff] [blame] | 369 | // Specifies libs used to initialize ART (java only, 'use_none' for no initialization) | 
|  | 370 | Use_platform_libs UsePlatformLibs `json:"use_platform_libs,omitempty"` | 
| David Fu | 4ad9bba | 2023-06-28 21:49:31 +0000 | [diff] [blame] | 371 | // Specifies whether fuzz target should check presubmitted code changes for crashes. | 
|  | 372 | // Defaults to false. | 
|  | 373 | Use_for_presubmit *bool `json:"use_for_presubmit,omitempty"` | 
| Cory Barker | 2490757 | 2023-07-18 21:19:53 +0000 | [diff] [blame] | 374 | // Specify which paths to exclude from fuzzing coverage reports | 
|  | 375 | Exclude_paths_from_reports []string `json:"exclude_paths_from_reports,omitempty"` | 
| hamzeh | c0a671f | 2021-07-22 12:05:08 -0700 | [diff] [blame] | 376 | } | 
|  | 377 |  | 
| Cory Barker | 9cfcf6d | 2022-07-22 17:22:02 +0000 | [diff] [blame] | 378 | type FuzzFrameworks struct { | 
|  | 379 | Afl       *bool | 
|  | 380 | Libfuzzer *bool | 
|  | 381 | Jazzer    *bool | 
|  | 382 | } | 
|  | 383 |  | 
| hamzeh | c0a671f | 2021-07-22 12:05:08 -0700 | [diff] [blame] | 384 | type FuzzProperties struct { | 
|  | 385 | // Optional list of seed files to be installed to the fuzz target's output | 
|  | 386 | // directory. | 
|  | 387 | Corpus []string `android:"path"` | 
|  | 388 | // Optional list of data files to be installed to the fuzz target's output | 
|  | 389 | // directory. Directory structure relative to the module is preserved. | 
|  | 390 | Data []string `android:"path"` | 
|  | 391 | // Optional dictionary to be installed to the fuzz target's output directory. | 
|  | 392 | Dictionary *string `android:"path"` | 
| Cory Barker | 9cfcf6d | 2022-07-22 17:22:02 +0000 | [diff] [blame] | 393 | // Define the fuzzing frameworks this fuzz target can be built for. If | 
|  | 394 | // empty then the fuzz target will be available to be  built for all fuzz | 
|  | 395 | // frameworks available | 
|  | 396 | Fuzzing_frameworks *FuzzFrameworks | 
| hamzeh | c0a671f | 2021-07-22 12:05:08 -0700 | [diff] [blame] | 397 | // Config for running the target on fuzzing infrastructure. | 
|  | 398 | Fuzz_config *FuzzConfig | 
|  | 399 | } | 
|  | 400 |  | 
| hamzeh | 41ad881 | 2021-07-07 14:00:07 -0700 | [diff] [blame] | 401 | type FuzzPackagedModule struct { | 
|  | 402 | FuzzProperties        FuzzProperties | 
|  | 403 | Dictionary            android.Path | 
|  | 404 | Corpus                android.Paths | 
|  | 405 | CorpusIntermediateDir android.Path | 
|  | 406 | Config                android.Path | 
|  | 407 | Data                  android.Paths | 
|  | 408 | DataIntermediateDir   android.Path | 
|  | 409 | } | 
|  | 410 |  | 
| Cory Barker | 9cfcf6d | 2022-07-22 17:22:02 +0000 | [diff] [blame] | 411 | func GetFramework(ctx android.LoadHookContext, lang Lang) Framework { | 
|  | 412 | framework := ctx.Config().Getenv("FUZZ_FRAMEWORK") | 
|  | 413 |  | 
|  | 414 | if lang == Cc { | 
|  | 415 | switch strings.ToLower(framework) { | 
|  | 416 | case "": | 
|  | 417 | return LibFuzzer | 
|  | 418 | case "libfuzzer": | 
|  | 419 | return LibFuzzer | 
|  | 420 | case "afl": | 
|  | 421 | return AFL | 
|  | 422 | } | 
|  | 423 | } else if lang == Rust { | 
|  | 424 | return LibFuzzer | 
|  | 425 | } else if lang == Java { | 
|  | 426 | return Jazzer | 
|  | 427 | } | 
|  | 428 |  | 
|  | 429 | ctx.ModuleErrorf(fmt.Sprintf("%s is not a valid fuzzing framework for %s", framework, lang)) | 
|  | 430 | return UnknownFramework | 
|  | 431 | } | 
|  | 432 |  | 
|  | 433 | func IsValidFrameworkForModule(targetFramework Framework, lang Lang, moduleFrameworks *FuzzFrameworks) bool { | 
|  | 434 | if targetFramework == UnknownFramework { | 
|  | 435 | return false | 
|  | 436 | } | 
|  | 437 |  | 
|  | 438 | if moduleFrameworks == nil { | 
|  | 439 | return true | 
|  | 440 | } | 
|  | 441 |  | 
|  | 442 | switch targetFramework { | 
|  | 443 | case LibFuzzer: | 
|  | 444 | return proptools.BoolDefault(moduleFrameworks.Libfuzzer, true) | 
|  | 445 | case AFL: | 
|  | 446 | return proptools.BoolDefault(moduleFrameworks.Afl, true) | 
|  | 447 | case Jazzer: | 
|  | 448 | return proptools.BoolDefault(moduleFrameworks.Jazzer, true) | 
|  | 449 | default: | 
|  | 450 | panic("%s is not supported as a fuzz framework") | 
|  | 451 | } | 
|  | 452 | } | 
|  | 453 |  | 
| hamzeh | 41ad881 | 2021-07-07 14:00:07 -0700 | [diff] [blame] | 454 | func IsValid(fuzzModule FuzzModule) bool { | 
|  | 455 | // Discard ramdisk + vendor_ramdisk + recovery modules, they're duplicates of | 
|  | 456 | // fuzz targets we're going to package anyway. | 
|  | 457 | if !fuzzModule.Enabled() || fuzzModule.InRamdisk() || fuzzModule.InVendorRamdisk() || fuzzModule.InRecovery() { | 
|  | 458 | return false | 
|  | 459 | } | 
|  | 460 |  | 
|  | 461 | // Discard modules that are in an unavailable namespace. | 
|  | 462 | if !fuzzModule.ExportedToMake() { | 
|  | 463 | return false | 
|  | 464 | } | 
|  | 465 |  | 
|  | 466 | return true | 
|  | 467 | } | 
|  | 468 |  | 
|  | 469 | func (s *FuzzPackager) PackageArtifacts(ctx android.SingletonContext, module android.Module, fuzzModule FuzzPackagedModule, archDir android.OutputPath, builder *android.RuleBuilder) []FileToZip { | 
|  | 470 | // Package the corpora into a zipfile. | 
|  | 471 | var files []FileToZip | 
|  | 472 | if fuzzModule.Corpus != nil { | 
|  | 473 | corpusZip := archDir.Join(ctx, module.Name()+"_seed_corpus.zip") | 
|  | 474 | command := builder.Command().BuiltTool("soong_zip"). | 
|  | 475 | Flag("-j"). | 
|  | 476 | FlagWithOutput("-o ", corpusZip) | 
|  | 477 | rspFile := corpusZip.ReplaceExtension(ctx, "rsp") | 
|  | 478 | command.FlagWithRspFileInputList("-r ", rspFile, fuzzModule.Corpus) | 
| Colin Cross | 80462dc | 2023-05-08 15:09:31 -0700 | [diff] [blame] | 479 | files = append(files, FileToZip{SourceFilePath: corpusZip}) | 
| hamzeh | 41ad881 | 2021-07-07 14:00:07 -0700 | [diff] [blame] | 480 | } | 
|  | 481 |  | 
|  | 482 | // Package the data into a zipfile. | 
|  | 483 | if fuzzModule.Data != nil { | 
|  | 484 | dataZip := archDir.Join(ctx, module.Name()+"_data.zip") | 
|  | 485 | command := builder.Command().BuiltTool("soong_zip"). | 
|  | 486 | FlagWithOutput("-o ", dataZip) | 
|  | 487 | for _, f := range fuzzModule.Data { | 
|  | 488 | intermediateDir := strings.TrimSuffix(f.String(), f.Rel()) | 
|  | 489 | command.FlagWithArg("-C ", intermediateDir) | 
|  | 490 | command.FlagWithInput("-f ", f) | 
|  | 491 | } | 
| Colin Cross | 80462dc | 2023-05-08 15:09:31 -0700 | [diff] [blame] | 492 | files = append(files, FileToZip{SourceFilePath: dataZip}) | 
| hamzeh | 41ad881 | 2021-07-07 14:00:07 -0700 | [diff] [blame] | 493 | } | 
|  | 494 |  | 
|  | 495 | // The dictionary. | 
|  | 496 | if fuzzModule.Dictionary != nil { | 
| Colin Cross | 80462dc | 2023-05-08 15:09:31 -0700 | [diff] [blame] | 497 | files = append(files, FileToZip{SourceFilePath: fuzzModule.Dictionary}) | 
| hamzeh | 41ad881 | 2021-07-07 14:00:07 -0700 | [diff] [blame] | 498 | } | 
|  | 499 |  | 
|  | 500 | // Additional fuzz config. | 
| hamzeh | e8a1bfa | 2022-06-21 12:22:06 -0700 | [diff] [blame] | 501 | if fuzzModule.Config != nil && IsValidConfig(fuzzModule, module.Name()) { | 
| Colin Cross | 80462dc | 2023-05-08 15:09:31 -0700 | [diff] [blame] | 502 | files = append(files, FileToZip{SourceFilePath: fuzzModule.Config}) | 
| hamzeh | 41ad881 | 2021-07-07 14:00:07 -0700 | [diff] [blame] | 503 | } | 
|  | 504 |  | 
|  | 505 | return files | 
|  | 506 | } | 
|  | 507 |  | 
|  | 508 | 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) { | 
|  | 509 | fuzzZip := archDir.Join(ctx, module.Name()+".zip") | 
|  | 510 |  | 
|  | 511 | command := builder.Command().BuiltTool("soong_zip"). | 
|  | 512 | Flag("-j"). | 
|  | 513 | FlagWithOutput("-o ", fuzzZip) | 
|  | 514 |  | 
|  | 515 | for _, file := range files { | 
|  | 516 | if file.DestinationPathPrefix != "" { | 
|  | 517 | command.FlagWithArg("-P ", file.DestinationPathPrefix) | 
|  | 518 | } else { | 
|  | 519 | command.Flag("-P ''") | 
|  | 520 | } | 
| Colin Cross | 80462dc | 2023-05-08 15:09:31 -0700 | [diff] [blame] | 521 | if file.DestinationPath != "" { | 
|  | 522 | command.FlagWithArg("-e ", file.DestinationPath) | 
|  | 523 | } | 
| hamzeh | 41ad881 | 2021-07-07 14:00:07 -0700 | [diff] [blame] | 524 | command.FlagWithInput("-f ", file.SourceFilePath) | 
|  | 525 | } | 
|  | 526 |  | 
|  | 527 | builder.Build("create-"+fuzzZip.String(), | 
|  | 528 | "Package "+module.Name()+" for "+archString+"-"+hostOrTargetString) | 
|  | 529 |  | 
|  | 530 | // Don't add modules to 'make haiku-rust' that are set to not be | 
|  | 531 | // exported to the fuzzing infrastructure. | 
|  | 532 | if config := fuzzModule.FuzzProperties.Fuzz_config; config != nil { | 
|  | 533 | if strings.Contains(hostOrTargetString, "host") && !BoolDefault(config.Fuzz_on_haiku_host, true) { | 
|  | 534 | return archDirs[archOs], false | 
|  | 535 | } else if !BoolDefault(config.Fuzz_on_haiku_device, true) { | 
|  | 536 | return archDirs[archOs], false | 
|  | 537 | } | 
|  | 538 | } | 
|  | 539 |  | 
|  | 540 | s.FuzzTargets[module.Name()] = true | 
| Colin Cross | 80462dc | 2023-05-08 15:09:31 -0700 | [diff] [blame] | 541 | archDirs[archOs] = append(archDirs[archOs], FileToZip{SourceFilePath: fuzzZip}) | 
| hamzeh | 41ad881 | 2021-07-07 14:00:07 -0700 | [diff] [blame] | 542 |  | 
|  | 543 | return archDirs[archOs], true | 
|  | 544 | } | 
|  | 545 |  | 
| hamzeh | c0a671f | 2021-07-22 12:05:08 -0700 | [diff] [blame] | 546 | func (f *FuzzConfig) String() string { | 
|  | 547 | b, err := json.Marshal(f) | 
|  | 548 | if err != nil { | 
|  | 549 | panic(err) | 
|  | 550 | } | 
|  | 551 |  | 
|  | 552 | return string(b) | 
|  | 553 | } | 
|  | 554 |  | 
| Cory Barker | 9cfcf6d | 2022-07-22 17:22:02 +0000 | [diff] [blame] | 555 | func (s *FuzzPackager) CreateFuzzPackage(ctx android.SingletonContext, archDirs map[ArchOs][]FileToZip, fuzzType Lang, pctx android.PackageContext) { | 
| hamzeh | 41ad881 | 2021-07-07 14:00:07 -0700 | [diff] [blame] | 556 | var archOsList []ArchOs | 
|  | 557 | for archOs := range archDirs { | 
|  | 558 | archOsList = append(archOsList, archOs) | 
|  | 559 | } | 
|  | 560 | sort.Slice(archOsList, func(i, j int) bool { return archOsList[i].Dir < archOsList[j].Dir }) | 
|  | 561 |  | 
|  | 562 | for _, archOs := range archOsList { | 
|  | 563 | filesToZip := archDirs[archOs] | 
|  | 564 | arch := archOs.Arch | 
|  | 565 | hostOrTarget := archOs.HostOrTarget | 
|  | 566 | builder := android.NewRuleBuilder(pctx, ctx) | 
|  | 567 | zipFileName := "fuzz-" + hostOrTarget + "-" + arch + ".zip" | 
| Cory Barker | a1da26f | 2022-06-07 20:12:06 +0000 | [diff] [blame] | 568 | if fuzzType == Rust { | 
| hamzeh | 41ad881 | 2021-07-07 14:00:07 -0700 | [diff] [blame] | 569 | zipFileName = "fuzz-rust-" + hostOrTarget + "-" + arch + ".zip" | 
|  | 570 | } | 
| Cory Barker | a1da26f | 2022-06-07 20:12:06 +0000 | [diff] [blame] | 571 | if fuzzType == Java { | 
| Muhammad Haseeb Ahmad | e380310 | 2022-01-10 21:37:07 +0000 | [diff] [blame] | 572 | zipFileName = "fuzz-java-" + hostOrTarget + "-" + arch + ".zip" | 
|  | 573 | } | 
| Cory Barker | 9cfcf6d | 2022-07-22 17:22:02 +0000 | [diff] [blame] | 574 |  | 
| hamzeh | 41ad881 | 2021-07-07 14:00:07 -0700 | [diff] [blame] | 575 | outputFile := android.PathForOutput(ctx, zipFileName) | 
|  | 576 |  | 
|  | 577 | s.Packages = append(s.Packages, outputFile) | 
|  | 578 |  | 
|  | 579 | command := builder.Command().BuiltTool("soong_zip"). | 
|  | 580 | Flag("-j"). | 
|  | 581 | FlagWithOutput("-o ", outputFile). | 
|  | 582 | Flag("-L 0") // No need to try and re-compress the zipfiles. | 
|  | 583 |  | 
|  | 584 | for _, fileToZip := range filesToZip { | 
| hamzeh | 41ad881 | 2021-07-07 14:00:07 -0700 | [diff] [blame] | 585 | if fileToZip.DestinationPathPrefix != "" { | 
|  | 586 | command.FlagWithArg("-P ", fileToZip.DestinationPathPrefix) | 
|  | 587 | } else { | 
|  | 588 | command.Flag("-P ''") | 
|  | 589 | } | 
|  | 590 | command.FlagWithInput("-f ", fileToZip.SourceFilePath) | 
|  | 591 |  | 
|  | 592 | } | 
|  | 593 | builder.Build("create-fuzz-package-"+arch+"-"+hostOrTarget, | 
|  | 594 | "Create fuzz target packages for "+arch+"-"+hostOrTarget) | 
|  | 595 | } | 
|  | 596 | } | 
|  | 597 |  | 
|  | 598 | func (s *FuzzPackager) PreallocateSlice(ctx android.MakeVarsContext, targets string) { | 
|  | 599 | fuzzTargets := make([]string, 0, len(s.FuzzTargets)) | 
|  | 600 | for target, _ := range s.FuzzTargets { | 
|  | 601 | fuzzTargets = append(fuzzTargets, target) | 
|  | 602 | } | 
| Cory Barker | a1da26f | 2022-06-07 20:12:06 +0000 | [diff] [blame] | 603 |  | 
| hamzeh | 41ad881 | 2021-07-07 14:00:07 -0700 | [diff] [blame] | 604 | sort.Strings(fuzzTargets) | 
|  | 605 | ctx.Strict(targets, strings.Join(fuzzTargets, " ")) | 
|  | 606 | } |