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

Commit 62cd0388 authored by Ivan Lozano's avatar Ivan Lozano
Browse files

rust: Support MTE memtag_heap sanitizer

This CL adds support for the MTE memtag_heap sanitizer. This is
controlled via inclusion of an ELF note.

Bug: 170672854
Test: Heap MTE-enabled Rust test binary triggers MTE
Change-Id: I2619818785e86a94667d02b30d102c83456b7925
parent 5482d6a9
Loading
Loading
Loading
Loading
+12 −10
Original line number Diff line number Diff line
@@ -81,7 +81,7 @@ const (
	intOverflow
	scs
	Fuzzer
	memtag_heap
	Memtag_heap
	cfi // cfi is last to prevent it running before incompatible mutators
)

@@ -92,7 +92,7 @@ var Sanitizers = []SanitizerType{
	intOverflow,
	scs,
	Fuzzer,
	memtag_heap,
	Memtag_heap,
	cfi, // cfi is last to prevent it running before incompatible mutators
}

@@ -111,7 +111,7 @@ func (t SanitizerType) variationName() string {
		return "cfi"
	case scs:
		return "scs"
	case memtag_heap:
	case Memtag_heap:
		return "memtag_heap"
	case Fuzzer:
		return "fuzzer"
@@ -127,7 +127,7 @@ func (t SanitizerType) name() string {
		return "address"
	case Hwasan:
		return "hwaddress"
	case memtag_heap:
	case Memtag_heap:
		return "memtag_heap"
	case tsan:
		return "thread"
@@ -149,7 +149,7 @@ func (t SanitizerType) registerMutators(ctx android.RegisterMutatorsContext) {
	case Asan, Hwasan, Fuzzer, scs, tsan, cfi:
		ctx.TopDown(t.variationName()+"_deps", sanitizerDepsMutator(t))
		ctx.BottomUp(t.variationName(), sanitizerMutator(t))
	case memtag_heap, intOverflow:
	case Memtag_heap, intOverflow:
		// do nothing
	default:
		panic(fmt.Errorf("unknown SanitizerType %d", t))
@@ -172,6 +172,8 @@ func (*Module) SanitizerSupported(t SanitizerType) bool {
		return true
	case Fuzzer:
		return true
	case Memtag_heap:
		return true
	default:
		return false
	}
@@ -460,7 +462,7 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) {
		s.Scs = nil
	}

	// memtag_heap is only implemented on AArch64.
	// Memtag_heap is only implemented on AArch64.
	if ctx.Arch().ArchType != android.Arm64 {
		s.Memtag_heap = nil
	}
@@ -798,7 +800,7 @@ func (sanitize *sanitize) getSanitizerBoolPtr(t SanitizerType) *bool {
		return sanitize.Properties.Sanitize.Cfi
	case scs:
		return sanitize.Properties.Sanitize.Scs
	case memtag_heap:
	case Memtag_heap:
		return sanitize.Properties.Sanitize.Memtag_heap
	case Fuzzer:
		return sanitize.Properties.Sanitize.Fuzzer
@@ -814,7 +816,7 @@ func (sanitize *sanitize) isUnsanitizedVariant() bool {
		!sanitize.isSanitizerEnabled(tsan) &&
		!sanitize.isSanitizerEnabled(cfi) &&
		!sanitize.isSanitizerEnabled(scs) &&
		!sanitize.isSanitizerEnabled(memtag_heap) &&
		!sanitize.isSanitizerEnabled(Memtag_heap) &&
		!sanitize.isSanitizerEnabled(Fuzzer)
}

@@ -844,7 +846,7 @@ func (sanitize *sanitize) SetSanitizer(t SanitizerType, b bool) {
		sanitize.Properties.Sanitize.Cfi = bPtr
	case scs:
		sanitize.Properties.Sanitize.Scs = bPtr
	case memtag_heap:
	case Memtag_heap:
		sanitize.Properties.Sanitize.Memtag_heap = bPtr
	case Fuzzer:
		sanitize.Properties.Sanitize.Fuzzer = bPtr
@@ -1133,7 +1135,7 @@ func sanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) {
			if lib, ok := snapshot.StaticLibs[noteDep]; ok {
				noteDep = lib
			}
			depTag := libraryDependencyTag{Kind: staticLibraryDependency, wholeStatic: true}
			depTag := StaticDepTag(true)
			variations := append(mctx.Target().Variations(),
				blueprint.Variation{Mutator: "link", Variation: "static"})
			if c.Device() {
+1 −0
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@ bootstrap_go_package {
        "project_json_test.go",
        "protobuf_test.go",
        "rust_test.go",
        "sanitize_test.go",
        "source_provider_test.go",
        "test_test.go",
        "vendor_snapshot_test.go",
+5 −0
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ type BinaryCompilerProperties struct {
type binaryInterface interface {
	binary() bool
	staticallyLinked() bool
	testBinary() bool
}

type binaryDecorator struct {
@@ -168,3 +169,7 @@ func (binary *binaryDecorator) binary() bool {
func (binary *binaryDecorator) staticallyLinked() bool {
	return Bool(binary.Properties.Static_executable)
}

func (binary *binaryDecorator) testBinary() bool {
	return false
}
+7 −0
Original line number Diff line number Diff line
@@ -442,3 +442,10 @@ func TestLibrarySizes(t *testing.T) {
	m.Output("libwaldo.dylib.so.bloaty.csv")
	m.Output("stripped/libwaldo.dylib.so.bloaty.csv")
}

func assertString(t *testing.T, got, expected string) {
	t.Helper()
	if got != expected {
		t.Errorf("expected %q got %q", expected, got)
	}
}
+92 −4
Original line number Diff line number Diff line
@@ -26,13 +26,28 @@ import (
	"android/soong/rust/config"
)

// 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"`

		// 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"`
@@ -99,7 +114,18 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) {
		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() {
@@ -109,6 +135,7 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) {
		arches := ctx.Config().SanitizeDeviceArch()
		if len(arches) == 0 || android.InList(ctx.Arch().ArchType.Name, arches) {
			globalSanitizers = ctx.Config().SanitizeDevice()
			globalSanitizersDiag = ctx.Config().SanitizeDeviceDiag()
		}
	}

@@ -123,6 +150,12 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) {
			}
		}

		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)
		}
@@ -131,6 +164,27 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) {
			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)
@@ -158,7 +212,12 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) {
		s.Address = nil
	}

	if ctx.Os() == android.Android && (Bool(s.Hwaddress) || Bool(s.Address)) {
	// 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
	}
}
@@ -198,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
@@ -225,9 +304,11 @@ func rustSanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) {
			deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "hwasan")}
		}

		if len(deps) > 0 {
			mctx.AddFarVariationDependencies(variations, depTag, deps...)
		}
	}
}

func (sanitize *sanitize) SetSanitizer(t cc.SanitizerType, b bool) {
	sanitizerSet := false
@@ -241,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))
	}
@@ -300,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
	}
@@ -330,6 +416,8 @@ func (mod *Module) SanitizerSupported(t cc.SanitizerType) bool {
			return false
		}
		return true
	case cc.Memtag_heap:
		return true
	default:
		return false
	}
Loading