fuzz.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. // Copyright 2016 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 cc
  15. import (
  16. "path/filepath"
  17. "sort"
  18. "strings"
  19. "github.com/google/blueprint/proptools"
  20. "android/soong/android"
  21. "android/soong/cc/config"
  22. "android/soong/fuzz"
  23. )
  24. func init() {
  25. android.RegisterModuleType("cc_fuzz", LibFuzzFactory)
  26. android.RegisterSingletonType("cc_fuzz_packaging", fuzzPackagingFactory)
  27. }
  28. type FuzzProperties struct {
  29. FuzzFramework fuzz.Framework `blueprint:"mutated"`
  30. }
  31. type fuzzer struct {
  32. Properties FuzzProperties
  33. }
  34. func (fuzzer *fuzzer) flags(ctx ModuleContext, flags Flags) Flags {
  35. if fuzzer.Properties.FuzzFramework == fuzz.AFL {
  36. flags.Local.CFlags = append(flags.Local.CFlags, []string{
  37. "-fsanitize-coverage=trace-pc-guard",
  38. "-Wno-unused-result",
  39. "-Wno-unused-parameter",
  40. "-Wno-unused-function",
  41. }...)
  42. }
  43. return flags
  44. }
  45. func (fuzzer *fuzzer) props() []interface{} {
  46. return []interface{}{&fuzzer.Properties}
  47. }
  48. func fuzzMutatorDeps(mctx android.TopDownMutatorContext) {
  49. currentModule, ok := mctx.Module().(*Module)
  50. if !ok {
  51. return
  52. }
  53. if currentModule.fuzzer == nil {
  54. return
  55. }
  56. mctx.WalkDeps(func(child android.Module, parent android.Module) bool {
  57. c, ok := child.(*Module)
  58. if !ok {
  59. return false
  60. }
  61. if c.sanitize == nil {
  62. return false
  63. }
  64. isFuzzerPointer := c.sanitize.getSanitizerBoolPtr(Fuzzer)
  65. if isFuzzerPointer == nil || !*isFuzzerPointer {
  66. return false
  67. }
  68. if c.fuzzer == nil {
  69. return false
  70. }
  71. c.fuzzer.Properties.FuzzFramework = currentModule.fuzzer.Properties.FuzzFramework
  72. return true
  73. })
  74. }
  75. // cc_fuzz creates a host/device fuzzer binary. Host binaries can be found at
  76. // $ANDROID_HOST_OUT/fuzz/, and device binaries can be found at /data/fuzz on
  77. // your device, or $ANDROID_PRODUCT_OUT/data/fuzz in your build tree.
  78. func LibFuzzFactory() android.Module {
  79. module := NewFuzzer(android.HostAndDeviceSupported)
  80. return module.Init()
  81. }
  82. type fuzzBinary struct {
  83. *binaryDecorator
  84. *baseCompiler
  85. fuzzPackagedModule fuzz.FuzzPackagedModule
  86. installedSharedDeps []string
  87. }
  88. func (fuzz *fuzzBinary) fuzzBinary() bool {
  89. return true
  90. }
  91. func (fuzz *fuzzBinary) linkerProps() []interface{} {
  92. props := fuzz.binaryDecorator.linkerProps()
  93. props = append(props, &fuzz.fuzzPackagedModule.FuzzProperties)
  94. return props
  95. }
  96. func (fuzz *fuzzBinary) linkerInit(ctx BaseModuleContext) {
  97. fuzz.binaryDecorator.linkerInit(ctx)
  98. }
  99. func (fuzzBin *fuzzBinary) linkerDeps(ctx DepsContext, deps Deps) Deps {
  100. if ctx.Config().Getenv("FUZZ_FRAMEWORK") == "AFL" {
  101. deps.HeaderLibs = append(deps.HeaderLibs, "libafl_headers")
  102. } else {
  103. deps.StaticLibs = append(deps.StaticLibs, config.LibFuzzerRuntimeLibrary(ctx.toolchain()))
  104. }
  105. deps = fuzzBin.binaryDecorator.linkerDeps(ctx, deps)
  106. return deps
  107. }
  108. func (fuzz *fuzzBinary) linkerFlags(ctx ModuleContext, flags Flags) Flags {
  109. flags = fuzz.binaryDecorator.linkerFlags(ctx, flags)
  110. // RunPaths on devices isn't instantiated by the base linker. `../lib` for
  111. // installed fuzz targets (both host and device), and `./lib` for fuzz
  112. // target packages.
  113. flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/../lib`)
  114. flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/lib`)
  115. return flags
  116. }
  117. func UnstrippedOutputFile(module android.Module) android.Path {
  118. if mod, ok := module.(LinkableInterface); ok {
  119. return mod.UnstrippedOutputFile()
  120. }
  121. panic("UnstrippedOutputFile called on non-LinkableInterface module: " + module.Name())
  122. }
  123. // IsValidSharedDependency takes a module and determines if it is a unique shared library
  124. // that should be installed in the fuzz target output directories. This function
  125. // returns true, unless:
  126. // - The module is not an installable shared library, or
  127. // - The module is a header or stub, or
  128. // - The module is a prebuilt and its source is available, or
  129. // - The module is a versioned member of an SDK snapshot.
  130. func IsValidSharedDependency(dependency android.Module) bool {
  131. // TODO(b/144090547): We should be parsing these modules using
  132. // ModuleDependencyTag instead of the current brute-force checking.
  133. linkable, ok := dependency.(LinkableInterface)
  134. if !ok || !linkable.CcLibraryInterface() {
  135. // Discard non-linkables.
  136. return false
  137. }
  138. if !linkable.Shared() {
  139. // Discard static libs.
  140. return false
  141. }
  142. if lib := moduleLibraryInterface(dependency); lib != nil && lib.buildStubs() && linkable.CcLibrary() {
  143. // Discard stubs libs (only CCLibrary variants). Prebuilt libraries should not
  144. // be excluded on the basis of they're not CCLibrary()'s.
  145. return false
  146. }
  147. // We discarded module stubs libraries above, but the LLNDK prebuilts stubs
  148. // libraries must be handled differently - by looking for the stubDecorator.
  149. // Discard LLNDK prebuilts stubs as well.
  150. if ccLibrary, isCcLibrary := dependency.(*Module); isCcLibrary {
  151. if _, isLLndkStubLibrary := ccLibrary.linker.(*stubDecorator); isLLndkStubLibrary {
  152. return false
  153. }
  154. // Discard installable:false libraries because they are expected to be absent
  155. // in runtime.
  156. if !proptools.BoolDefault(ccLibrary.Installable(), true) {
  157. return false
  158. }
  159. }
  160. // If the same library is present both as source and a prebuilt we must pick
  161. // only one to avoid a conflict. Always prefer the source since the prebuilt
  162. // probably won't be built with sanitizers enabled.
  163. if prebuilt := android.GetEmbeddedPrebuilt(dependency); prebuilt != nil && prebuilt.SourceExists() {
  164. return false
  165. }
  166. // Discard versioned members of SDK snapshots, because they will conflict with
  167. // unversioned ones.
  168. if sdkMember, ok := dependency.(android.SdkAware); ok && !sdkMember.ContainingSdk().Unversioned() {
  169. return false
  170. }
  171. return true
  172. }
  173. func sharedLibraryInstallLocation(
  174. libraryPath android.Path, isHost bool, fuzzDir string, archString string) string {
  175. installLocation := "$(PRODUCT_OUT)/data"
  176. if isHost {
  177. installLocation = "$(HOST_OUT)"
  178. }
  179. installLocation = filepath.Join(
  180. installLocation, fuzzDir, archString, "lib", libraryPath.Base())
  181. return installLocation
  182. }
  183. // Get the device-only shared library symbols install directory.
  184. func sharedLibrarySymbolsInstallLocation(libraryPath android.Path, fuzzDir string, archString string) string {
  185. return filepath.Join("$(PRODUCT_OUT)/symbols/data/", fuzzDir, archString, "/lib/", libraryPath.Base())
  186. }
  187. func (fuzzBin *fuzzBinary) install(ctx ModuleContext, file android.Path) {
  188. installBase := "fuzz"
  189. fuzzBin.binaryDecorator.baseInstaller.dir = filepath.Join(
  190. installBase, ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
  191. fuzzBin.binaryDecorator.baseInstaller.dir64 = filepath.Join(
  192. installBase, ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
  193. fuzzBin.binaryDecorator.baseInstaller.install(ctx, file)
  194. fuzzBin.fuzzPackagedModule.Corpus = android.PathsForModuleSrc(ctx, fuzzBin.fuzzPackagedModule.FuzzProperties.Corpus)
  195. builder := android.NewRuleBuilder(pctx, ctx)
  196. intermediateDir := android.PathForModuleOut(ctx, "corpus")
  197. for _, entry := range fuzzBin.fuzzPackagedModule.Corpus {
  198. builder.Command().Text("cp").
  199. Input(entry).
  200. Output(intermediateDir.Join(ctx, entry.Base()))
  201. }
  202. builder.Build("copy_corpus", "copy corpus")
  203. fuzzBin.fuzzPackagedModule.CorpusIntermediateDir = intermediateDir
  204. fuzzBin.fuzzPackagedModule.Data = android.PathsForModuleSrc(ctx, fuzzBin.fuzzPackagedModule.FuzzProperties.Data)
  205. builder = android.NewRuleBuilder(pctx, ctx)
  206. intermediateDir = android.PathForModuleOut(ctx, "data")
  207. for _, entry := range fuzzBin.fuzzPackagedModule.Data {
  208. builder.Command().Text("cp").
  209. Input(entry).
  210. Output(intermediateDir.Join(ctx, entry.Rel()))
  211. }
  212. builder.Build("copy_data", "copy data")
  213. fuzzBin.fuzzPackagedModule.DataIntermediateDir = intermediateDir
  214. if fuzzBin.fuzzPackagedModule.FuzzProperties.Dictionary != nil {
  215. fuzzBin.fuzzPackagedModule.Dictionary = android.PathForModuleSrc(ctx, *fuzzBin.fuzzPackagedModule.FuzzProperties.Dictionary)
  216. if fuzzBin.fuzzPackagedModule.Dictionary.Ext() != ".dict" {
  217. ctx.PropertyErrorf("dictionary",
  218. "Fuzzer dictionary %q does not have '.dict' extension",
  219. fuzzBin.fuzzPackagedModule.Dictionary.String())
  220. }
  221. }
  222. if fuzzBin.fuzzPackagedModule.FuzzProperties.Fuzz_config != nil {
  223. configPath := android.PathForModuleOut(ctx, "config").Join(ctx, "config.json")
  224. android.WriteFileRule(ctx, configPath, fuzzBin.fuzzPackagedModule.FuzzProperties.Fuzz_config.String())
  225. fuzzBin.fuzzPackagedModule.Config = configPath
  226. }
  227. // Grab the list of required shared libraries.
  228. seen := make(map[string]bool)
  229. var sharedLibraries android.Paths
  230. ctx.WalkDeps(func(child, parent android.Module) bool {
  231. if seen[child.Name()] {
  232. return false
  233. }
  234. seen[child.Name()] = true
  235. if IsValidSharedDependency(child) {
  236. sharedLibraries = append(sharedLibraries, child.(*Module).UnstrippedOutputFile())
  237. return true
  238. }
  239. return false
  240. })
  241. for _, lib := range sharedLibraries {
  242. fuzzBin.installedSharedDeps = append(fuzzBin.installedSharedDeps,
  243. sharedLibraryInstallLocation(
  244. lib, ctx.Host(), installBase, ctx.Arch().ArchType.String()))
  245. // Also add the dependency on the shared library symbols dir.
  246. if !ctx.Host() {
  247. fuzzBin.installedSharedDeps = append(fuzzBin.installedSharedDeps,
  248. sharedLibrarySymbolsInstallLocation(lib, installBase, ctx.Arch().ArchType.String()))
  249. }
  250. }
  251. }
  252. func NewFuzzer(hod android.HostOrDeviceSupported) *Module {
  253. module, binary := newBinary(hod, false)
  254. baseInstallerPath := "fuzz"
  255. binary.baseInstaller = NewBaseInstaller(baseInstallerPath, baseInstallerPath, InstallInData)
  256. module.sanitize.SetSanitizer(Fuzzer, true)
  257. fuzzBin := &fuzzBinary{
  258. binaryDecorator: binary,
  259. baseCompiler: NewBaseCompiler(),
  260. }
  261. module.compiler = fuzzBin
  262. module.linker = fuzzBin
  263. module.installer = fuzzBin
  264. module.fuzzer.Properties.FuzzFramework = fuzz.LibFuzzer
  265. // The fuzzer runtime is not present for darwin host modules, disable cc_fuzz modules when targeting darwin.
  266. android.AddLoadHook(module, func(ctx android.LoadHookContext) {
  267. disableDarwinAndLinuxBionic := struct {
  268. Target struct {
  269. Darwin struct {
  270. Enabled *bool
  271. }
  272. Linux_bionic struct {
  273. Enabled *bool
  274. }
  275. }
  276. }{}
  277. disableDarwinAndLinuxBionic.Target.Darwin.Enabled = BoolPtr(false)
  278. disableDarwinAndLinuxBionic.Target.Linux_bionic.Enabled = BoolPtr(false)
  279. ctx.AppendProperties(&disableDarwinAndLinuxBionic)
  280. targetFramework := fuzz.GetFramework(ctx, fuzz.Cc)
  281. if !fuzz.IsValidFrameworkForModule(targetFramework, fuzz.Cc, fuzzBin.fuzzPackagedModule.FuzzProperties.Fuzzing_frameworks) {
  282. ctx.Module().Disable()
  283. return
  284. }
  285. if targetFramework == fuzz.AFL {
  286. fuzzBin.baseCompiler.Properties.Srcs = append(fuzzBin.baseCompiler.Properties.Srcs, ":aflpp_driver", ":afl-compiler-rt")
  287. module.fuzzer.Properties.FuzzFramework = fuzz.AFL
  288. }
  289. })
  290. return module
  291. }
  292. // Responsible for generating GNU Make rules that package fuzz targets into
  293. // their architecture & target/host specific zip file.
  294. type ccFuzzPackager struct {
  295. fuzz.FuzzPackager
  296. fuzzPackagingArchModules string
  297. fuzzTargetSharedDepsInstallPairs string
  298. allFuzzTargetsName string
  299. }
  300. func fuzzPackagingFactory() android.Singleton {
  301. fuzzPackager := &ccFuzzPackager{
  302. fuzzPackagingArchModules: "SOONG_FUZZ_PACKAGING_ARCH_MODULES",
  303. fuzzTargetSharedDepsInstallPairs: "FUZZ_TARGET_SHARED_DEPS_INSTALL_PAIRS",
  304. allFuzzTargetsName: "ALL_FUZZ_TARGETS",
  305. }
  306. return fuzzPackager
  307. }
  308. func (s *ccFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
  309. // Map between each architecture + host/device combination, and the files that
  310. // need to be packaged (in the tuple of {source file, destination folder in
  311. // archive}).
  312. archDirs := make(map[fuzz.ArchOs][]fuzz.FileToZip)
  313. // List of individual fuzz targets, so that 'make fuzz' also installs the targets
  314. // to the correct output directories as well.
  315. s.FuzzTargets = make(map[string]bool)
  316. // Map tracking whether each shared library has an install rule to avoid duplicate install rules from
  317. // multiple fuzzers that depend on the same shared library.
  318. sharedLibraryInstalled := make(map[string]bool)
  319. ctx.VisitAllModules(func(module android.Module) {
  320. ccModule, ok := module.(*Module)
  321. if !ok || ccModule.Properties.PreventInstall {
  322. return
  323. }
  324. // Discard non-fuzz targets.
  325. if ok := fuzz.IsValid(ccModule.FuzzModule); !ok {
  326. return
  327. }
  328. sharedLibsInstallDirPrefix := "lib"
  329. fuzzModule, ok := ccModule.compiler.(*fuzzBinary)
  330. if !ok {
  331. return
  332. }
  333. hostOrTargetString := "target"
  334. if ccModule.Host() {
  335. hostOrTargetString = "host"
  336. }
  337. fpm := fuzz.FuzzPackagedModule{}
  338. if ok {
  339. fpm = fuzzModule.fuzzPackagedModule
  340. }
  341. intermediatePath := "fuzz"
  342. archString := ccModule.Arch().ArchType.String()
  343. archDir := android.PathForIntermediates(ctx, intermediatePath, hostOrTargetString, archString)
  344. archOs := fuzz.ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()}
  345. // Grab the list of required shared libraries.
  346. sharedLibraries := fuzz.CollectAllSharedDependencies(ctx, module, UnstrippedOutputFile, IsValidSharedDependency)
  347. var files []fuzz.FileToZip
  348. builder := android.NewRuleBuilder(pctx, ctx)
  349. // Package the corpus, data, dict and config into a zipfile.
  350. files = s.PackageArtifacts(ctx, module, fpm, archDir, builder)
  351. // Package shared libraries
  352. files = append(files, GetSharedLibsToZip(sharedLibraries, ccModule, &s.FuzzPackager, archString, sharedLibsInstallDirPrefix, &sharedLibraryInstalled)...)
  353. // The executable.
  354. files = append(files, fuzz.FileToZip{ccModule.UnstrippedOutputFile(), ""})
  355. archDirs[archOs], ok = s.BuildZipFile(ctx, module, fpm, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs)
  356. if !ok {
  357. return
  358. }
  359. })
  360. s.CreateFuzzPackage(ctx, archDirs, fuzz.Cc, pctx)
  361. }
  362. func (s *ccFuzzPackager) MakeVars(ctx android.MakeVarsContext) {
  363. packages := s.Packages.Strings()
  364. sort.Strings(packages)
  365. sort.Strings(s.FuzzPackager.SharedLibInstallStrings)
  366. // TODO(mitchp): Migrate this to use MakeVarsContext::DistForGoal() when it's
  367. // ready to handle phony targets created in Soong. In the meantime, this
  368. // exports the phony 'fuzz' target and dependencies on packages to
  369. // core/main.mk so that we can use dist-for-goals.
  370. ctx.Strict(s.fuzzPackagingArchModules, strings.Join(packages, " "))
  371. ctx.Strict(s.fuzzTargetSharedDepsInstallPairs,
  372. strings.Join(s.FuzzPackager.SharedLibInstallStrings, " "))
  373. // Preallocate the slice of fuzz targets to minimise memory allocations.
  374. s.PreallocateSlice(ctx, s.allFuzzTargetsName)
  375. }
  376. // GetSharedLibsToZip finds and marks all the transiently-dependent shared libraries for
  377. // packaging.
  378. func GetSharedLibsToZip(sharedLibraries android.Paths, module LinkableInterface, s *fuzz.FuzzPackager, archString string, destinationPathPrefix string, sharedLibraryInstalled *map[string]bool) []fuzz.FileToZip {
  379. var files []fuzz.FileToZip
  380. fuzzDir := "fuzz"
  381. for _, library := range sharedLibraries {
  382. files = append(files, fuzz.FileToZip{library, destinationPathPrefix})
  383. // For each architecture-specific shared library dependency, we need to
  384. // install it to the output directory. Setup the install destination here,
  385. // which will be used by $(copy-many-files) in the Make backend.
  386. installDestination := sharedLibraryInstallLocation(
  387. library, module.Host(), fuzzDir, archString)
  388. if (*sharedLibraryInstalled)[installDestination] {
  389. continue
  390. }
  391. (*sharedLibraryInstalled)[installDestination] = true
  392. // Escape all the variables, as the install destination here will be called
  393. // via. $(eval) in Make.
  394. installDestination = strings.ReplaceAll(
  395. installDestination, "$", "$$")
  396. s.SharedLibInstallStrings = append(s.SharedLibInstallStrings,
  397. library.String()+":"+installDestination)
  398. // Ensure that on device, the library is also reinstalled to the /symbols/
  399. // dir. Symbolized DSO's are always installed to the device when fuzzing, but
  400. // we want symbolization tools (like `stack`) to be able to find the symbols
  401. // in $ANDROID_PRODUCT_OUT/symbols automagically.
  402. if !module.Host() {
  403. symbolsInstallDestination := sharedLibrarySymbolsInstallLocation(library, fuzzDir, archString)
  404. symbolsInstallDestination = strings.ReplaceAll(symbolsInstallDestination, "$", "$$")
  405. s.SharedLibInstallStrings = append(s.SharedLibInstallStrings,
  406. library.String()+":"+symbolsInstallDestination)
  407. }
  408. }
  409. return files
  410. }