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

Commit 5482d6a9 authored by Ivan Lozano's avatar Ivan Lozano
Browse files

rust: Support global sanitizers

This CL adds Rust support for the SANITIZE_TARGET options.

This CL includes a couple small fixes to related to HWASAN, ASAN,
ensuring that the Never sanitize property is respected. Notably,
additional llvm-args are passed to ensure that HWASAN-ified Rust/C
interop works correctly.

Bug: 170672854
Bug: 204915322
Test: SANITIZE_TARGET globally applies hwasan to Rust targets
Change-Id: Ia904d07b4618f72cdc95c51f88961905c240ac53
parent a3bd9639
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -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)
+1 −1
Original line number Diff line number Diff line
@@ -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 {
+78 −17
Original line number Diff line number Diff line
@@ -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,24 +211,19 @@ 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 {
			// 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
+9 −1
Original line number Diff line number Diff line
@@ -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)
}