diff options
Diffstat (limited to 'rust/sanitize.go')
-rw-r--r-- | rust/sanitize.go | 189 |
1 files changed, 169 insertions, 20 deletions
diff --git a/rust/sanitize.go b/rust/sanitize.go index baa383da6..fdb342d40 100644 --- a/rust/sanitize.go +++ b/rust/sanitize.go @@ -15,20 +15,39 @@ 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" ) +// TODO: When Rust has sanitizer-parity with CC, deduplicate this struct type SanitizeProperties struct { // enable AddressSanitizer, HWAddressSanitizer, and others. Sanitize struct { Address *bool `android:"arch_variant"` Hwaddress *bool `android:"arch_variant"` - Fuzzer *bool `android:"arch_variant"` - Never *bool `android:"arch_variant"` + + // Memory-tagging, only available on arm64 + // if diag.memtag unset or false, enables async memory tagging + Memtag_heap *bool `android:"arch_variant"` + Fuzzer *bool `android:"arch_variant"` + Never *bool `android:"arch_variant"` + + // Sanitizers to run in the diagnostic mode (as opposed to the release mode). + // Replaces abort() on error with a human-readable error message. + // Address and Thread sanitizers always run in diagnostic mode. + Diag struct { + // Memory-tagging, only available on arm64 + // requires sanitizer.memtag: true + // if set, enables sync memory tagging + Memtag_heap *bool `android:"arch_variant"` + } } SanitizerEnabled bool `blueprint:"mutated"` SanitizeDep bool `blueprint:"mutated"` @@ -59,9 +78,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 +107,85 @@ 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 + } + + // rust_test targets default to SYNC MemTag unless explicitly set to ASYNC (via diag: {Memtag_heap}). + if binary, ok := ctx.RustModule().compiler.(binaryInterface); ok && binary.testBinary() { + if s.Memtag_heap == nil { + s.Memtag_heap = proptools.BoolPtr(true) + } + if s.Diag.Memtag_heap == nil { + s.Diag.Memtag_heap = proptools.BoolPtr(true) + } + } + + var globalSanitizers []string + var globalSanitizersDiag []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() + globalSanitizersDiag = ctx.Config().SanitizeDeviceDiag() + } + } + + 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("memtag_heap", globalSanitizers); found && s.Memtag_heap == nil { + if !ctx.Config().MemtagHeapDisabledForPath(ctx.ModuleDir()) { + s.Memtag_heap = 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) + } + + // Global Diag Sanitizers + if found, globalSanitizersDiag = android.RemoveFromList("memtag_heap", globalSanitizersDiag); found && + s.Diag.Memtag_heap == nil && Bool(s.Memtag_heap) { + s.Diag.Memtag_heap = proptools.BoolPtr(true) + } + } + + // Enable Memtag for all components in the include paths (for Aarch64 only) + if ctx.Arch().ArchType == android.Arm64 { + if ctx.Config().MemtagHeapSyncEnabledForPath(ctx.ModuleDir()) { + if s.Memtag_heap == nil { + s.Memtag_heap = proptools.BoolPtr(true) + } + if s.Diag.Memtag_heap == nil { + s.Diag.Memtag_heap = proptools.BoolPtr(true) + } + } else if ctx.Config().MemtagHeapAsyncEnabledForPath(ctx.ModuleDir()) { + if s.Memtag_heap == nil { + s.Memtag_heap = proptools.BoolPtr(true) + } + } + } // TODO:(b/178369775) // For now sanitizing is only supported on devices @@ -96,7 +202,22 @@ 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 + } + + // Memtag_heap is only implemented on AArch64. + if ctx.Arch().ArchType != android.Arm64 { + s.Memtag_heap = nil + } + + if ctx.Os() == android.Android && (Bool(s.Hwaddress) || Bool(s.Address) || Bool(s.Memtag_heap)) { sanitize.Properties.SanitizerEnabled = true } } @@ -136,6 +257,26 @@ func rustSanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) { return } + if Bool(mod.sanitize.Properties.Sanitize.Memtag_heap) && mod.Binary() { + noteDep := "note_memtag_heap_async" + if Bool(mod.sanitize.Properties.Sanitize.Diag.Memtag_heap) { + noteDep = "note_memtag_heap_sync" + } + // If we're using snapshots, redirect to snapshot whenever possible + // TODO(b/178470649): clean manual snapshot redirections + snapshot := mctx.Provider(cc.SnapshotInfoProvider).(cc.SnapshotInfo) + if lib, ok := snapshot.StaticLibs[noteDep]; ok { + noteDep = lib + } + depTag := cc.StaticDepTag(true) + variations := append(mctx.Target().Variations(), + blueprint.Variation{Mutator: "link", Variation: "static"}) + if mod.Device() { + variations = append(variations, mod.ImageVariation()) + } + mctx.AddFarVariationDependencies(variations, depTag, noteDep) + } + variations := mctx.Target().Variations() var depTag blueprint.DependencyTag var deps []string @@ -149,26 +290,23 @@ 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...) + if len(deps) > 0 { + mctx.AddFarVariationDependencies(variations, depTag, deps...) + } } } @@ -184,6 +322,9 @@ func (sanitize *sanitize) SetSanitizer(t cc.SanitizerType, b bool) { case cc.Hwasan: sanitize.Properties.Sanitize.Hwaddress = boolPtr(b) sanitizerSet = true + case cc.Memtag_heap: + sanitize.Properties.Sanitize.Memtag_heap = boolPtr(b) + sanitizerSet = true default: panic(fmt.Errorf("setting unsupported sanitizerType %d", t)) } @@ -243,6 +384,8 @@ func (sanitize *sanitize) getSanitizerBoolPtr(t cc.SanitizerType) *bool { return sanitize.Properties.Sanitize.Address case cc.Hwasan: return sanitize.Properties.Sanitize.Hwaddress + case cc.Memtag_heap: + return sanitize.Properties.Sanitize.Memtag_heap default: return nil } @@ -268,6 +411,12 @@ 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 + case cc.Memtag_heap: return true default: return false |