fuzz.go 14 KB

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