diff --git a/cc/sanitize.go b/cc/sanitize.go index f6a9d5bc4..605425268 100644 --- a/cc/sanitize.go +++ b/cc/sanitize.go @@ -1303,6 +1303,10 @@ var _ PlatformSanitizeable = (*Module)(nil) func sanitizerMutator(t SanitizerType) func(android.BottomUpMutatorContext) { return func(mctx android.BottomUpMutatorContext) { if c, ok := mctx.Module().(PlatformSanitizeable); ok && c.SanitizePropDefined() { + + // Make sure we're not setting CFI to any value if it's not supported. + cfiSupported := mctx.Module().(PlatformSanitizeable).SanitizerSupported(cfi) + if c.Binary() && c.IsSanitizerEnabled(t) { modules := mctx.CreateVariations(t.variationName()) modules[0].(PlatformSanitizeable).SetSanitizer(t, true) @@ -1323,7 +1327,6 @@ func sanitizerMutator(t SanitizerType) func(android.BottomUpMutatorContext) { // is redirected to the sanitized variant of the dependent module. defaultVariation := t.variationName() // Not all PlatformSanitizeable modules support the CFI sanitizer - cfiSupported := mctx.Module().(PlatformSanitizeable).SanitizerSupported(cfi) mctx.SetDefaultDependencyVariation(&defaultVariation) modules := mctx.CreateVariations("", t.variationName()) @@ -1370,7 +1373,7 @@ func sanitizerMutator(t SanitizerType) func(android.BottomUpMutatorContext) { modules[0].(PlatformSanitizeable).SetInSanitizerDir() } - if mctx.Device() && t.incompatibleWithCfi() { + if mctx.Device() && t.incompatibleWithCfi() && cfiSupported { // TODO: Make sure that cfi mutator runs "after" any of the sanitizers that // are incompatible with cfi modules[0].(PlatformSanitizeable).SetSanitizer(cfi, false) diff --git a/rust/fuzz.go b/rust/fuzz.go index a628b6158..44ac68a62 100644 --- a/rust/fuzz.go +++ b/rust/fuzz.go @@ -36,7 +36,7 @@ type fuzzDecorator struct { fuzzPackagedModule fuzz.FuzzPackagedModule } -var _ compiler = (*binaryDecorator)(nil) +var _ compiler = (*fuzzDecorator)(nil) // rust_binary produces a binary that is runnable on a device. func RustFuzzFactory() android.Module { diff --git a/rust/sanitize.go b/rust/sanitize.go index baa383da6..5b7597e14 100644 --- a/rust/sanitize.go +++ b/rust/sanitize.go @@ -15,11 +15,15 @@ package rust import ( + "fmt" + "strings" + + "github.com/google/blueprint" + "github.com/google/blueprint/proptools" + "android/soong/android" "android/soong/cc" "android/soong/rust/config" - "fmt" - "github.com/google/blueprint" ) type SanitizeProperties struct { @@ -59,9 +63,18 @@ var asanFlags = []string{ "-Z sanitizer=address", } +// See cc/sanitize.go's hwasanGlobalOptions for global hwasan options. var hwasanFlags = []string{ "-Z sanitizer=hwaddress", "-C target-feature=+tagged-globals", + + // Flags from cc/sanitize.go hwasanFlags + "-C llvm-args=--aarch64-enable-global-isel-at-O=-1", + "-C llvm-args=-fast-isel=false", + "-C llvm-args=-instcombine-lower-dbg-declare=0", + + // Additional flags for HWASAN-ified Rust/C interop + "-C llvm-args=--hwasan-with-ifunc", } func boolPtr(v bool) *bool { @@ -79,7 +92,46 @@ func (sanitize *sanitize) props() []interface{} { } func (sanitize *sanitize) begin(ctx BaseModuleContext) { - s := sanitize.Properties.Sanitize + s := &sanitize.Properties.Sanitize + + // Never always wins. + if Bool(s.Never) { + return + } + + var globalSanitizers []string + + if ctx.Host() { + if !ctx.Windows() { + globalSanitizers = ctx.Config().SanitizeHost() + } + } else { + arches := ctx.Config().SanitizeDeviceArch() + if len(arches) == 0 || android.InList(ctx.Arch().ArchType.Name, arches) { + globalSanitizers = ctx.Config().SanitizeDevice() + } + } + + if len(globalSanitizers) > 0 { + var found bool + + // Global Sanitizers + if found, globalSanitizers = android.RemoveFromList("hwaddress", globalSanitizers); found && s.Hwaddress == nil { + // TODO(b/180495975): HWASan for static Rust binaries isn't supported yet. + if !ctx.RustModule().StaticExecutable() { + s.Hwaddress = proptools.BoolPtr(true) + } + } + + if found, globalSanitizers = android.RemoveFromList("address", globalSanitizers); found && s.Address == nil { + s.Address = proptools.BoolPtr(true) + } + + if found, globalSanitizers = android.RemoveFromList("fuzzer", globalSanitizers); found && s.Fuzzer == nil { + s.Fuzzer = proptools.BoolPtr(true) + } + + } // TODO:(b/178369775) // For now sanitizing is only supported on devices @@ -96,7 +148,17 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) { s.Hwaddress = nil } - if ctx.Os() == android.Android && Bool(s.Hwaddress) { + // HWASan ramdisk (which is built from recovery) goes over some bootloader limit. + // Keep libc instrumented so that ramdisk / vendor_ramdisk / recovery can run hwasan-instrumented code if necessary. + if (ctx.RustModule().InRamdisk() || ctx.RustModule().InVendorRamdisk() || ctx.RustModule().InRecovery()) && !strings.HasPrefix(ctx.ModuleDir(), "bionic/libc") { + s.Hwaddress = nil + } + + if Bool(s.Hwaddress) { + s.Address = nil + } + + if ctx.Os() == android.Android && (Bool(s.Hwaddress) || Bool(s.Address)) { sanitize.Properties.SanitizerEnabled = true } } @@ -149,23 +211,18 @@ func rustSanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) { } else if mod.IsSanitizerEnabled(cc.Hwasan) || (mod.IsSanitizerEnabled(cc.Fuzzer) && mctx.Arch().ArchType == android.Arm64) { // TODO(b/180495975): HWASan for static Rust binaries isn't supported yet. - if binary, ok := mod.compiler.(*binaryDecorator); ok { - if Bool(binary.Properties.Static_executable) { + if binary, ok := mod.compiler.(binaryInterface); ok { + if binary.staticallyLinked() { mctx.ModuleErrorf("HWASan is not supported for static Rust executables yet.") } } - if mod.StaticallyLinked() { - variations = append(variations, - blueprint.Variation{Mutator: "link", Variation: "static"}) - depTag = cc.StaticDepTag(false) - deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "hwasan_static")} - } else { - variations = append(variations, - blueprint.Variation{Mutator: "link", Variation: "shared"}) - depTag = cc.SharedDepTag() - deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "hwasan")} - } + // Always link against the shared library -- static binaries will pull in the static + // library during final link if necessary + variations = append(variations, + blueprint.Variation{Mutator: "link", Variation: "shared"}) + depTag = cc.SharedDepTag() + deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "hwasan")} } mctx.AddFarVariationDependencies(variations, depTag, deps...) @@ -268,6 +325,10 @@ func (mod *Module) SanitizerSupported(t cc.SanitizerType) bool { case cc.Asan: return true case cc.Hwasan: + // TODO(b/180495975): HWASan for static Rust binaries isn't supported yet. + if mod.StaticExecutable() { + return false + } return true default: return false diff --git a/rust/testing.go b/rust/testing.go index 94cdd9dcd..abcf23544 100644 --- a/rust/testing.go +++ b/rust/testing.go @@ -151,7 +151,12 @@ func GatherRequiredDepsForTest() string { no_libcrt: true, nocrt: true, system_shared_libs: [], - export_include_dirs: ["libprotobuf-cpp-full-includes"], + } + cc_library { + name: "libclang_rt.hwasan_static-aarch64-android", + no_libcrt: true, + nocrt: true, + system_shared_libs: [], } rust_library { name: "libstd", @@ -246,5 +251,8 @@ func registerRequiredBuildComponentsForTest(ctx android.RegistrationContext) { ctx.BottomUp("rust_begin", BeginMutator).Parallel() }) ctx.RegisterSingletonType("rust_project_generator", rustProjectGeneratorSingleton) + ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) { + ctx.BottomUp("rust_sanitizers", rustSanitizerRuntimeMutator).Parallel() + }) registerRustSnapshotModules(ctx) }