Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cecb7546 authored by Cory Barker's avatar Cory Barker
Browse files

Updated the way we build AFL++ fuzz binaries

Test: Built AFL fuzzers individually and built all using haiku command
and built libfuzzers individually and also by using haiku command. Ran
selected fuzzers manually to ensure fuzzing still worked.

Description: Previously we needed to add cc_afl_fuzz to build an afl fuzz binary,
however, to turn current libFuzzers into AFL fuzzers this would required
an update to each Android.bp file which is a lot of work, and would also
require an approval from each Android.bp file owner, which is even more
work.

To get around this (and also to match how AFL fuzzers are built in G3)
we will build AFL++ fuzz binaries by command line option FUZZ_FRAMEWORK.
When FUZZ_FRAMEWORK=AFL is set, all cc_fuzz modules will be built
for AFL rather than libFuzzer. Devs can also specify if a cc_fuzz module
is only for libFuzzer or AFL by using fuzzing_frameworks. If
fuzzing_frameworks is left blank then it will be assumed that the
cc_fuzz module can be built for all available fuzzing frameworks.

Change-Id: Ia7a8224627f2de61606b410d1d1a56d7bdc0955f
parent b3e7dfbd
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -62,7 +62,6 @@ func RegisterCCBuildComponents(ctx android.RegistrationContext) {
		ctx.BottomUp("sanitize_runtime", sanitizerRuntimeMutator).Parallel()

		ctx.TopDown("fuzz_deps", fuzzMutatorDeps)
		ctx.BottomUp("fuzz", fuzzMutator)

		ctx.BottomUp("coverage", coverageMutator).Parallel()

+28 −31
Original line number Diff line number Diff line
@@ -3343,8 +3343,8 @@ func TestErrorsIfAModuleDependsOnDisabled(t *testing.T) {
}

func TestAFLFuzzTarget(t *testing.T) {
	ctx := testCc(t, `
		cc_afl_fuzz {
	bp := `
		cc_fuzz {
			name: "test_afl_fuzz_target",
			srcs: ["foo.c"],
			host_supported: true,
@@ -3354,17 +3354,10 @@ func TestAFLFuzzTarget(t *testing.T) {
			shared_libs: [
				"afl_fuzz_shared_lib",
			],
		}
		cc_fuzz {
			name: "test_fuzz_target",
			srcs: ["foo.c"],
			static_libs: [
				"afl_fuzz_static_lib",
				"libfuzzer_only_static_lib",
			],
			shared_libs: [
				"afl_fuzz_shared_lib",
			],
			fuzzing_frameworks: {
				afl: true,
				libfuzzer: false,
			},
		}
		cc_library {
			name: "afl_fuzz_static_lib",
@@ -3409,12 +3402,19 @@ func TestAFLFuzzTarget(t *testing.T) {
			host_supported: true,
			srcs: ["second_file.c"],
		}
		filegroup {
		cc_object {
			name: "aflpp_driver",
			host_supported: true,
			srcs: [
				"aflpp_driver.c",
			],
		}`)
		}`

	testEnv := map[string]string{
		"FUZZ_FRAMEWORK": "AFL",
	}

	ctx := android.GroupFixturePreparers(prepareForCcTest, android.FixtureMergeEnv(testEnv)).RunTestWithBp(t, bp)

	checkPcGuardFlag := func(
		modName string, variantName string, shouldHave bool) {
@@ -3434,31 +3434,28 @@ func TestAFLFuzzTarget(t *testing.T) {
		}
	}

	for _, vnt := range ctx.ModuleVariantsForTests("libfuzzer_only_static_lib") {
		if strings.Contains(vnt, "fuzzer_afl") {
			t.Errorf("libfuzzer_only_static_lib has afl variant and should not")
		}
	}

	moduleName := "test_afl_fuzz_target"
	variantName := "android_arm64_armv8-a_fuzzer_afl"
	checkPcGuardFlag(moduleName, variantName, true)
	hostVariant := "linux_glibc_x86_64"
	armVariant := "android_arm64_armv8-a"
	checkPcGuardFlag(moduleName, armVariant+"_fuzzer", true)
	checkPcGuardFlag(moduleName, hostVariant+"_fuzzer", true)

	moduleName = "afl_fuzz_static_lib"
	variantName = "android_arm64_armv8-a_static"
	checkPcGuardFlag(moduleName, variantName, false)
	checkPcGuardFlag(moduleName, variantName+"_fuzzer", false)
	checkPcGuardFlag(moduleName, variantName+"_fuzzer_afl", true)
	checkPcGuardFlag(moduleName, armVariant+"_static", false)
	checkPcGuardFlag(moduleName, armVariant+"_static_fuzzer", true)
	checkPcGuardFlag(moduleName, hostVariant+"_static", false)
	checkPcGuardFlag(moduleName, hostVariant+"_static_fuzzer", true)

	moduleName = "second_static_lib"
	checkPcGuardFlag(moduleName, variantName, false)
	checkPcGuardFlag(moduleName, variantName+"_fuzzer", false)
	checkPcGuardFlag(moduleName, variantName+"_fuzzer_afl", true)
	checkPcGuardFlag(moduleName, armVariant+"_static", false)
	checkPcGuardFlag(moduleName, armVariant+"_static_fuzzer", true)
	checkPcGuardFlag(moduleName, hostVariant+"_static", false)
	checkPcGuardFlag(moduleName, hostVariant+"_static_fuzzer", true)

	ctx.ModuleForTests("afl_fuzz_shared_lib",
		"android_arm64_armv8-a_shared").Rule("cc")
	ctx.ModuleForTests("afl_fuzz_shared_lib",
		"android_arm64_armv8-a_shared_fuzzer_afl").Rule("cc")
		"android_arm64_armv8-a_shared_fuzzer").Rule("cc")
}

// Simple smoke test for the cc_fuzz target that ensures the rule compiles
+32 −86
Original line number Diff line number Diff line
@@ -27,15 +27,12 @@ import (
)

func init() {
	android.RegisterModuleType("cc_afl_fuzz", AFLFuzzFactory)
	android.RegisterModuleType("cc_fuzz", LibFuzzFactory)
	android.RegisterSingletonType("cc_fuzz_packaging", fuzzPackagingFactory)
	android.RegisterSingletonType("cc_afl_fuzz_packaging", fuzzAFLPackagingFactory)
}

type FuzzProperties struct {
	AFLEnabled  bool `blueprint:"mutated"`
	AFLAddFlags bool `blueprint:"mutated"`
	FuzzFramework fuzz.Framework `blueprint:"mutated"`
}

type fuzzer struct {
@@ -43,8 +40,13 @@ type fuzzer struct {
}

func (fuzzer *fuzzer) flags(ctx ModuleContext, flags Flags) Flags {
	if fuzzer.Properties.AFLAddFlags {
		flags.Local.CFlags = append(flags.Local.CFlags, "-fsanitize-coverage=trace-pc-guard")
	if fuzzer.Properties.FuzzFramework == fuzz.AFL {
		flags.Local.CFlags = append(flags.Local.CFlags, []string{
			"-fsanitize-coverage=trace-pc-guard",
			"-Wno-unused-result",
			"-Wno-unused-parameter",
			"-Wno-unused-function",
		}...)
	}

	return flags
@@ -60,7 +62,7 @@ func fuzzMutatorDeps(mctx android.TopDownMutatorContext) {
		return
	}

	if currentModule.fuzzer == nil || !currentModule.fuzzer.Properties.AFLEnabled {
	if currentModule.fuzzer == nil {
		return
	}

@@ -83,48 +85,16 @@ func fuzzMutatorDeps(mctx android.TopDownMutatorContext) {
			return false
		}

		c.fuzzer.Properties.AFLEnabled = true
		c.fuzzer.Properties.AFLAddFlags = true
		c.fuzzer.Properties.FuzzFramework = currentModule.fuzzer.Properties.FuzzFramework
		return true
	})
}

func fuzzMutator(mctx android.BottomUpMutatorContext) {
	if c, ok := mctx.Module().(*Module); ok && c.fuzzer != nil {
		if !c.fuzzer.Properties.AFLEnabled {
			return
		}

		if c.Binary() {
			m := mctx.CreateVariations("afl")
			m[0].(*Module).fuzzer.Properties.AFLEnabled = true
			m[0].(*Module).fuzzer.Properties.AFLAddFlags = true
		} else {
			m := mctx.CreateVariations("", "afl")
			m[0].(*Module).fuzzer.Properties.AFLEnabled = false
			m[0].(*Module).fuzzer.Properties.AFLAddFlags = false

			m[1].(*Module).fuzzer.Properties.AFLEnabled = true
			m[1].(*Module).fuzzer.Properties.AFLAddFlags = true
		}
	}
}

// cc_fuzz creates a host/device fuzzer binary. Host binaries can be found at
// $ANDROID_HOST_OUT/fuzz/, and device binaries can be found at /data/fuzz on
// your device, or $ANDROID_PRODUCT_OUT/data/fuzz in your build tree.
func LibFuzzFactory() android.Module {
	module := NewFuzzer(android.HostAndDeviceSupported, fuzz.Cc)
	return module.Init()
}

// cc_afl_fuzz creates a host/device AFL++ fuzzer binary.
// AFL++ is an open source framework used to fuzz libraries
// Host binaries can be found at $ANDROID_HOST_OUT/afl_fuzz/ and device
// binaries can be found at $ANDROID_PRODUCT_OUT/data/afl_fuzz in your
// build tree
func AFLFuzzFactory() android.Module {
	module := NewFuzzer(android.HostAndDeviceSupported, fuzz.AFL)
	module := NewFuzzer(android.HostAndDeviceSupported)
	return module.Init()
}

@@ -133,7 +103,6 @@ type fuzzBinary struct {
	*baseCompiler
	fuzzPackagedModule  fuzz.FuzzPackagedModule
	installedSharedDeps []string
	fuzzType            fuzz.FuzzType
}

func (fuzz *fuzzBinary) fuzzBinary() bool {
@@ -143,6 +112,7 @@ func (fuzz *fuzzBinary) fuzzBinary() bool {
func (fuzz *fuzzBinary) linkerProps() []interface{} {
	props := fuzz.binaryDecorator.linkerProps()
	props = append(props, &fuzz.fuzzPackagedModule.FuzzProperties)

	return props
}

@@ -151,17 +121,15 @@ func (fuzz *fuzzBinary) linkerInit(ctx BaseModuleContext) {
}

func (fuzzBin *fuzzBinary) linkerDeps(ctx DepsContext, deps Deps) Deps {
	if fuzzBin.fuzzType == fuzz.AFL {
	if ctx.Config().Getenv("FUZZ_FRAMEWORK") == "AFL" {
		deps.HeaderLibs = append(deps.HeaderLibs, "libafl_headers")
		deps = fuzzBin.binaryDecorator.linkerDeps(ctx, deps)
		return deps

	} else {
		deps.StaticLibs = append(deps.StaticLibs, config.LibFuzzerRuntimeLibrary(ctx.toolchain()))
	}

	deps = fuzzBin.binaryDecorator.linkerDeps(ctx, deps)
	return deps
}
}

func (fuzz *fuzzBinary) linkerFlags(ctx ModuleContext, flags Flags) Flags {
	flags = fuzz.binaryDecorator.linkerFlags(ctx, flags)
@@ -257,9 +225,6 @@ func sharedLibrarySymbolsInstallLocation(libraryPath android.Path, fuzzDir strin

func (fuzzBin *fuzzBinary) install(ctx ModuleContext, file android.Path) {
	installBase := "fuzz"
	if fuzzBin.fuzzType == fuzz.AFL {
		installBase = "afl_fuzz"
	}

	fuzzBin.binaryDecorator.baseInstaller.dir = filepath.Join(
		installBase, ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
@@ -333,12 +298,9 @@ func (fuzzBin *fuzzBinary) install(ctx ModuleContext, file android.Path) {
	}
}

func NewFuzzer(hod android.HostOrDeviceSupported, fuzzType fuzz.FuzzType) *Module {
func NewFuzzer(hod android.HostOrDeviceSupported) *Module {
	module, binary := newBinary(hod, false)
	baseInstallerPath := "fuzz"
	if fuzzType == fuzz.AFL {
		baseInstallerPath = "afl_fuzz"
	}

	binary.baseInstaller = NewBaseInstaller(baseInstallerPath, baseInstallerPath, InstallInData)
	module.sanitize.SetSanitizer(Fuzzer, true)
@@ -346,12 +308,13 @@ func NewFuzzer(hod android.HostOrDeviceSupported, fuzzType fuzz.FuzzType) *Modul
	fuzzBin := &fuzzBinary{
		binaryDecorator: binary,
		baseCompiler:    NewBaseCompiler(),
		fuzzType:        fuzzType,
	}
	module.compiler = fuzzBin
	module.linker = fuzzBin
	module.installer = fuzzBin

	module.fuzzer.Properties.FuzzFramework = fuzz.LibFuzzer

	// The fuzzer runtime is not present for darwin host modules, disable cc_fuzz modules when targeting darwin.
	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
		disableDarwinAndLinuxBionic := struct {
@@ -367,18 +330,18 @@ func NewFuzzer(hod android.HostOrDeviceSupported, fuzzType fuzz.FuzzType) *Modul
		disableDarwinAndLinuxBionic.Target.Darwin.Enabled = BoolPtr(false)
		disableDarwinAndLinuxBionic.Target.Linux_bionic.Enabled = BoolPtr(false)
		ctx.AppendProperties(&disableDarwinAndLinuxBionic)
	})

	if fuzzType == fuzz.AFL {
		// Add cc_objects to Srcs
		targetFramework := fuzz.GetFramework(ctx, fuzz.Cc)
		if !fuzz.IsValidFrameworkForModule(targetFramework, fuzz.Cc, fuzzBin.fuzzPackagedModule.FuzzProperties.Fuzzing_frameworks) {
			ctx.Module().Disable()
			return
		}

		if targetFramework == fuzz.AFL {
			fuzzBin.baseCompiler.Properties.Srcs = append(fuzzBin.baseCompiler.Properties.Srcs, ":aflpp_driver", ":afl-compiler-rt")
		module.fuzzer.Properties.AFLEnabled = true
		module.compiler.appendCflags([]string{
			"-Wno-unused-result",
			"-Wno-unused-parameter",
			"-Wno-unused-function",
		})
			module.fuzzer.Properties.FuzzFramework = fuzz.AFL
		}
	})

	return module
}
@@ -399,17 +362,6 @@ func fuzzPackagingFactory() android.Singleton {
		fuzzTargetSharedDepsInstallPairs: "FUZZ_TARGET_SHARED_DEPS_INSTALL_PAIRS",
		allFuzzTargetsName:               "ALL_FUZZ_TARGETS",
	}
	fuzzPackager.FuzzType = fuzz.Cc
	return fuzzPackager
}

func fuzzAFLPackagingFactory() android.Singleton {
	fuzzPackager := &ccFuzzPackager{
		fuzzPackagingArchModules:         "SOONG_AFL_FUZZ_PACKAGING_ARCH_MODULES",
		fuzzTargetSharedDepsInstallPairs: "AFL_FUZZ_TARGET_SHARED_DEPS_INSTALL_PAIRS",
		allFuzzTargetsName:               "ALL_AFL_FUZZ_TARGETS",
	}
	fuzzPackager.FuzzType = fuzz.AFL
	return fuzzPackager
}

@@ -440,7 +392,7 @@ func (s *ccFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {

		sharedLibsInstallDirPrefix := "lib"
		fuzzModule, ok := ccModule.compiler.(*fuzzBinary)
		if !ok || fuzzModule.fuzzType != s.FuzzType {
		if !ok {
			return
		}

@@ -455,9 +407,6 @@ func (s *ccFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
		}

		intermediatePath := "fuzz"
		if s.FuzzType == fuzz.AFL {
			intermediatePath = "afl_fuzz"
		}

		archString := ccModule.Arch().ArchType.String()
		archDir := android.PathForIntermediates(ctx, intermediatePath, hostOrTargetString, archString)
@@ -484,7 +433,7 @@ func (s *ccFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
		}
	})

	s.CreateFuzzPackage(ctx, archDirs, s.FuzzType, pctx)
	s.CreateFuzzPackage(ctx, archDirs, fuzz.Cc, pctx)
}

func (s *ccFuzzPackager) MakeVars(ctx android.MakeVarsContext) {
@@ -511,9 +460,6 @@ func GetSharedLibsToZip(sharedLibraries android.Paths, module LinkableInterface,
	var files []fuzz.FileToZip

	fuzzDir := "fuzz"
	if s.FuzzType == fuzz.AFL {
		fuzzDir = "afl_fuzz"
	}

	for _, library := range sharedLibraries {
		files = append(files, fuzz.FileToZip{library, destinationPathPrefix})
+0 −2
Original line number Diff line number Diff line
@@ -535,7 +535,6 @@ var PrepareForTestWithCcBuildComponents = android.GroupFixturePreparers(
	android.FixtureRegisterWithContext(RegisterRequiredBuildComponentsForTest),
	android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
		ctx.RegisterModuleType("cc_fuzz", LibFuzzFactory)
		ctx.RegisterModuleType("cc_afl_fuzz", AFLFuzzFactory)
		ctx.RegisterModuleType("cc_test", TestFactory)
		ctx.RegisterModuleType("cc_test_library", TestLibraryFactory)
		ctx.RegisterModuleType("vndk_prebuilt_shared", VndkPrebuiltSharedFactory)
@@ -650,7 +649,6 @@ func CreateTestContext(config android.Config) *android.TestContext {
	ctx := android.NewTestArchContext(config)
	genrule.RegisterGenruleBuildComponents(ctx)
	ctx.RegisterModuleType("cc_fuzz", LibFuzzFactory)
	ctx.RegisterModuleType("cc_afl_fuzz", AFLFuzzFactory)
	ctx.RegisterModuleType("cc_test", TestFactory)
	ctx.RegisterModuleType("cc_test_library", TestLibraryFactory)
	ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
+68 −10
Original line number Diff line number Diff line
@@ -27,13 +27,21 @@ import (
	"android/soong/android"
)

type FuzzType string
type Lang string

const (
	Cc   FuzzType = ""
	Rust FuzzType = "rust"
	Java FuzzType = "java"
	AFL  FuzzType = "AFL"
	Cc   Lang = "cc"
	Rust Lang = "rust"
	Java Lang = "java"
)

type Framework string

const (
	AFL              Framework = "afl"
	LibFuzzer        Framework = "libfuzzer"
	Jazzer           Framework = "jazzer"
	UnknownFramework Framework = "unknownframework"
)

var BoolDefault = proptools.BoolDefault
@@ -48,7 +56,6 @@ type FuzzPackager struct {
	Packages                android.Paths
	FuzzTargets             map[string]bool
	SharedLibInstallStrings []string
	FuzzType                FuzzType
}

type FileToZip struct {
@@ -146,6 +153,12 @@ type FuzzConfig struct {
	IsJni *bool `json:"is_jni,omitempty"`
}

type FuzzFrameworks struct {
	Afl       *bool
	Libfuzzer *bool
	Jazzer    *bool
}

type FuzzProperties struct {
	// Optional list of seed files to be installed to the fuzz target's output
	// directory.
@@ -155,6 +168,10 @@ type FuzzProperties struct {
	Data []string `android:"path"`
	// Optional dictionary to be installed to the fuzz target's output directory.
	Dictionary *string `android:"path"`
	// Define the fuzzing frameworks this fuzz target can be built for. If
	// empty then the fuzz target will be available to be  built for all fuzz
	// frameworks available
	Fuzzing_frameworks *FuzzFrameworks
	// Config for running the target on fuzzing infrastructure.
	Fuzz_config *FuzzConfig
}
@@ -169,6 +186,49 @@ type FuzzPackagedModule struct {
	DataIntermediateDir   android.Path
}

func GetFramework(ctx android.LoadHookContext, lang Lang) Framework {
	framework := ctx.Config().Getenv("FUZZ_FRAMEWORK")

	if lang == Cc {
		switch strings.ToLower(framework) {
		case "":
			return LibFuzzer
		case "libfuzzer":
			return LibFuzzer
		case "afl":
			return AFL
		}
	} else if lang == Rust {
		return LibFuzzer
	} else if lang == Java {
		return Jazzer
	}

	ctx.ModuleErrorf(fmt.Sprintf("%s is not a valid fuzzing framework for %s", framework, lang))
	return UnknownFramework
}

func IsValidFrameworkForModule(targetFramework Framework, lang Lang, moduleFrameworks *FuzzFrameworks) bool {
	if targetFramework == UnknownFramework {
		return false
	}

	if moduleFrameworks == nil {
		return true
	}

	switch targetFramework {
	case LibFuzzer:
		return proptools.BoolDefault(moduleFrameworks.Libfuzzer, true)
	case AFL:
		return proptools.BoolDefault(moduleFrameworks.Afl, true)
	case Jazzer:
		return proptools.BoolDefault(moduleFrameworks.Jazzer, true)
	default:
		panic("%s is not supported as a fuzz framework")
	}
}

func IsValid(fuzzModule FuzzModule) bool {
	// Discard ramdisk + vendor_ramdisk + recovery modules, they're duplicates of
	// fuzz targets we're going to package anyway.
@@ -267,7 +327,7 @@ func (f *FuzzConfig) String() string {
	return string(b)
}

func (s *FuzzPackager) CreateFuzzPackage(ctx android.SingletonContext, archDirs map[ArchOs][]FileToZip, fuzzType FuzzType, pctx android.PackageContext) {
func (s *FuzzPackager) CreateFuzzPackage(ctx android.SingletonContext, archDirs map[ArchOs][]FileToZip, fuzzType Lang, pctx android.PackageContext) {
	var archOsList []ArchOs
	for archOs := range archDirs {
		archOsList = append(archOsList, archOs)
@@ -286,9 +346,7 @@ func (s *FuzzPackager) CreateFuzzPackage(ctx android.SingletonContext, archDirs
		if fuzzType == Java {
			zipFileName = "fuzz-java-" + hostOrTarget + "-" + arch + ".zip"
		}
		if fuzzType == AFL {
			zipFileName = "fuzz-afl-" + hostOrTarget + "-" + arch + ".zip"
		}

		outputFile := android.PathForOutput(ctx, zipFileName)

		s.Packages = append(s.Packages, outputFile)