Support "memtag_heap" sanitizer.
Memtag_heap adds an ELF note that enables MTE heap tagging in
bionic/scudo. Ignored on non-executables. With diagnostic
(diag:{memtag_heap:true}) enables the SYNC mode, otherwise - ASYNC mode.
Memtag_heap defaults to set (with diag) on cc_test targets, unset
otherwise. Ignored on non MTE-compatible hardware.
Bug: b/135772972
Test: soong tests
Change-Id: I88fd0f159e609e17bd13487749980a1ba02cb91c
diff --git a/cc/cc.go b/cc/cc.go
index c0c85f9..ca2bd4f 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -420,6 +420,7 @@
type ModuleContextIntf interface {
static() bool
staticBinary() bool
+ testBinary() bool
header() bool
binary() bool
object() bool
@@ -1261,6 +1262,10 @@
return ctx.mod.staticBinary()
}
+func (ctx *moduleContextImpl) testBinary() bool {
+ return ctx.mod.testBinary()
+}
+
func (ctx *moduleContextImpl) header() bool {
return ctx.mod.Header()
}
@@ -2961,6 +2966,15 @@
return false
}
+func (c *Module) testBinary() bool {
+ if test, ok := c.linker.(interface {
+ testBinary() bool
+ }); ok {
+ return test.testBinary()
+ }
+ return false
+}
+
// Header returns true if the module is a header-only variant. (See cc/library.go header()).
func (c *Module) Header() bool {
if h, ok := c.linker.(interface {
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 3502d5f..1ab1b82 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -4461,3 +4461,105 @@
t.Errorf("aidl command %q does not contain %q", aidlCommand, expectedAidlFlag)
}
}
+
+func checkHasImplicitDep(t *testing.T, m android.TestingModule, name string) {
+ implicits := m.Rule("ld").Implicits
+ for _, lib := range implicits {
+ if strings.Contains(lib.Rel(), name) {
+ return
+ }
+ }
+
+ t.Errorf("%q is not found in implicit deps of module %q", name, m.Module().(*Module).Name())
+}
+
+func checkDoesNotHaveImplicitDep(t *testing.T, m android.TestingModule, name string) {
+ implicits := m.Rule("ld").Implicits
+ for _, lib := range implicits {
+ if strings.Contains(lib.Rel(), name) {
+ t.Errorf("%q is found in implicit deps of module %q", name, m.Module().(*Module).Name())
+ }
+ }
+}
+
+func TestSanitizeMemtagHeap(t *testing.T) {
+ ctx := testCc(t, `
+ cc_library_static {
+ name: "libstatic",
+ sanitize: { memtag_heap: true },
+ }
+
+ cc_library_shared {
+ name: "libshared",
+ sanitize: { memtag_heap: true },
+ }
+
+ cc_library {
+ name: "libboth",
+ sanitize: { memtag_heap: true },
+ }
+
+ cc_binary {
+ name: "binary",
+ shared_libs: [ "libshared" ],
+ static_libs: [ "libstatic" ],
+ }
+
+ cc_binary {
+ name: "binary_true",
+ sanitize: { memtag_heap: true },
+ }
+
+ cc_binary {
+ name: "binary_true_sync",
+ sanitize: { memtag_heap: true, diag: { memtag_heap: true }, },
+ }
+
+ cc_binary {
+ name: "binary_false",
+ sanitize: { memtag_heap: false },
+ }
+
+ cc_test {
+ name: "test",
+ gtest: false,
+ }
+
+ cc_test {
+ name: "test_true",
+ gtest: false,
+ sanitize: { memtag_heap: true },
+ }
+
+ cc_test {
+ name: "test_false",
+ gtest: false,
+ sanitize: { memtag_heap: false },
+ }
+
+ cc_test {
+ name: "test_true_async",
+ gtest: false,
+ sanitize: { memtag_heap: true, diag: { memtag_heap: false } },
+ }
+
+ `)
+
+ variant := "android_arm64_armv8-a"
+ note_async := "note_memtag_heap_async"
+ note_sync := "note_memtag_heap_sync"
+ note_any := "note_memtag_"
+
+ checkDoesNotHaveImplicitDep(t, ctx.ModuleForTests("libshared", "android_arm64_armv8-a_shared"), note_any)
+ checkDoesNotHaveImplicitDep(t, ctx.ModuleForTests("libboth", "android_arm64_armv8-a_shared"), note_any)
+
+ checkDoesNotHaveImplicitDep(t, ctx.ModuleForTests("binary", variant), note_any)
+ checkHasImplicitDep(t, ctx.ModuleForTests("binary_true", variant), note_async)
+ checkHasImplicitDep(t, ctx.ModuleForTests("binary_true_sync", variant), note_sync)
+ checkDoesNotHaveImplicitDep(t, ctx.ModuleForTests("binary_false", variant), note_any)
+
+ checkHasImplicitDep(t, ctx.ModuleForTests("test", variant), note_sync)
+ checkHasImplicitDep(t, ctx.ModuleForTests("test_true", variant), note_async)
+ checkDoesNotHaveImplicitDep(t, ctx.ModuleForTests("test_false", variant), note_any)
+ checkHasImplicitDep(t, ctx.ModuleForTests("test_true_async", variant), note_async)
+}
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 5992611..13e1780 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -89,6 +89,7 @@
cfi
scs
Fuzzer
+ memtag_heap
)
// Name of the sanitizer variation for this sanitizer type
@@ -106,6 +107,8 @@
return "cfi"
case scs:
return "scs"
+ case memtag_heap:
+ return "memtag_heap"
case Fuzzer:
return "fuzzer"
default:
@@ -120,6 +123,8 @@
return "address"
case hwasan:
return "hwaddress"
+ case memtag_heap:
+ return "memtag_heap"
case tsan:
return "thread"
case intOverflow:
@@ -179,6 +184,7 @@
Integer_overflow *bool `android:"arch_variant"`
Scudo *bool `android:"arch_variant"`
Scs *bool `android:"arch_variant"`
+ Memtag_heap *bool `android:"arch_variant"`
// A modifier for ASAN and HWASAN for write only instrumentation
Writeonly *bool `android:"arch_variant"`
@@ -190,6 +196,7 @@
Undefined *bool `android:"arch_variant"`
Cfi *bool `android:"arch_variant"`
Integer_overflow *bool `android:"arch_variant"`
+ Memtag_heap *bool `android:"arch_variant"`
Misc_undefined []string `android:"arch_variant"`
No_recover []string `android:"arch_variant"`
} `android:"arch_variant"`
@@ -330,6 +337,9 @@
}
s.Writeonly = boolPtr(true)
}
+ if found, globalSanitizers = removeFromList("memtag_heap", globalSanitizers); found && s.Memtag_heap == nil {
+ s.Memtag_heap = boolPtr(true)
+ }
if len(globalSanitizers) > 0 {
ctx.ModuleErrorf("unknown global sanitizer option %s", globalSanitizers[0])
@@ -351,6 +361,12 @@
}
}
+ // cc_test targets default to SYNC MemTag.
+ if ctx.testBinary() && s.Memtag_heap == nil {
+ s.Memtag_heap = boolPtr(true)
+ s.Diag.Memtag_heap = boolPtr(true)
+ }
+
// Enable CFI for all components in the include paths (for Aarch64 only)
if s.Cfi == nil && ctx.Config().CFIEnabledForPath(ctx.ModuleDir()) && ctx.Arch().ArchType == android.Arm64 {
s.Cfi = boolPtr(true)
@@ -381,6 +397,11 @@
s.Scs = nil
}
+ // memtag_heap is only implemented on AArch64.
+ if ctx.Arch().ArchType != android.Arm64 {
+ s.Memtag_heap = nil
+ }
+
// Also disable CFI if ASAN is enabled.
if Bool(s.Address) || Bool(s.Hwaddress) {
s.Cfi = boolPtr(false)
@@ -435,7 +456,7 @@
if ctx.Os() != android.Windows && (Bool(s.All_undefined) || Bool(s.Undefined) || Bool(s.Address) || Bool(s.Thread) ||
Bool(s.Fuzzer) || Bool(s.Safestack) || Bool(s.Cfi) || Bool(s.Integer_overflow) || len(s.Misc_undefined) > 0 ||
- Bool(s.Scudo) || Bool(s.Hwaddress) || Bool(s.Scs)) {
+ Bool(s.Scudo) || Bool(s.Hwaddress) || Bool(s.Scs) || Bool(s.Memtag_heap)) {
sanitize.Properties.SanitizerEnabled = true
}
@@ -717,6 +738,8 @@
return sanitize.Properties.Sanitize.Cfi
case scs:
return sanitize.Properties.Sanitize.Scs
+ case memtag_heap:
+ return sanitize.Properties.Sanitize.Memtag_heap
case Fuzzer:
return sanitize.Properties.Sanitize.Fuzzer
default:
@@ -731,6 +754,7 @@
!sanitize.isSanitizerEnabled(tsan) &&
!sanitize.isSanitizerEnabled(cfi) &&
!sanitize.isSanitizerEnabled(scs) &&
+ !sanitize.isSanitizerEnabled(memtag_heap) &&
!sanitize.isSanitizerEnabled(Fuzzer)
}
@@ -756,6 +780,8 @@
sanitize.Properties.Sanitize.Cfi = boolPtr(b)
case scs:
sanitize.Properties.Sanitize.Scs = boolPtr(b)
+ case memtag_heap:
+ sanitize.Properties.Sanitize.Memtag_heap = boolPtr(b)
case Fuzzer:
sanitize.Properties.Sanitize.Fuzzer = boolPtr(b)
default:
@@ -1032,6 +1058,20 @@
sanitizers = append(sanitizers, "shadow-call-stack")
}
+ if Bool(c.sanitize.Properties.Sanitize.Memtag_heap) && c.binary() {
+ noteDep := "note_memtag_heap_async"
+ if Bool(c.sanitize.Properties.Sanitize.Diag.Memtag_heap) {
+ noteDep = "note_memtag_heap_sync"
+ }
+ depTag := libraryDependencyTag{Kind: staticLibraryDependency, wholeStatic: true}
+ variations := append(mctx.Target().Variations(),
+ blueprint.Variation{Mutator: "link", Variation: "static"})
+ if c.Device() {
+ variations = append(variations, c.ImageVariation())
+ }
+ mctx.AddFarVariationDependencies(variations, depTag, noteDep)
+ }
+
if Bool(c.sanitize.Properties.Sanitize.Fuzzer) {
sanitizers = append(sanitizers, "fuzzer-no-link")
}
diff --git a/cc/test.go b/cc/test.go
index 4ff5bf6..f715a8d 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -236,6 +236,10 @@
return BoolDefault(test.Properties.Gtest, true)
}
+func (test *testDecorator) testBinary() bool {
+ return true
+}
+
func (test *testDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags {
if !test.gtest() {
return flags
diff --git a/cc/testing.go b/cc/testing.go
index 8d92ea2..903f76c 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -445,6 +445,14 @@
stl: "none",
system_shared_libs: [],
}
+
+ cc_library_static {
+ name: "note_memtag_heap_async",
+ }
+
+ cc_library_static {
+ name: "note_memtag_heap_sync",
+ }
`
supportLinuxBionic := false