fuzz_common.go 21 KB

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