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
This commit is contained in:
Evgenii Stepanov 2020-04-28 15:09:12 -07:00
parent 016370b146
commit 193ac2eb96
5 changed files with 169 additions and 1 deletions

View File

@ -420,6 +420,7 @@ type VendorProperties struct {
type ModuleContextIntf interface {
static() bool
staticBinary() bool
testBinary() bool
header() bool
binary() bool
object() bool
@ -1261,6 +1262,10 @@ func (ctx *moduleContextImpl) staticBinary() bool {
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 @@ func (c *Module) staticBinary() bool {
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 {

View File

@ -4461,3 +4461,105 @@ func TestAidlFlagsPassedToTheAidlCompiler(t *testing.T) {
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)
}

View File

@ -89,6 +89,7 @@ const (
cfi
scs
Fuzzer
memtag_heap
)
// Name of the sanitizer variation for this sanitizer type
@ -106,6 +107,8 @@ func (t SanitizerType) variationName() string {
return "cfi"
case scs:
return "scs"
case memtag_heap:
return "memtag_heap"
case Fuzzer:
return "fuzzer"
default:
@ -120,6 +123,8 @@ func (t SanitizerType) name() string {
return "address"
case hwasan:
return "hwaddress"
case memtag_heap:
return "memtag_heap"
case tsan:
return "thread"
case intOverflow:
@ -179,6 +184,7 @@ type SanitizeUserProps struct {
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 @@ type SanitizeUserProps struct {
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 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) {
}
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 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) {
}
}
// 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 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) {
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 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) {
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 @@ func (sanitize *sanitize) getSanitizerBoolPtr(t SanitizerType) *bool {
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 @@ func (sanitize *sanitize) isUnsanitizedVariant() bool {
!sanitize.isSanitizerEnabled(tsan) &&
!sanitize.isSanitizerEnabled(cfi) &&
!sanitize.isSanitizerEnabled(scs) &&
!sanitize.isSanitizerEnabled(memtag_heap) &&
!sanitize.isSanitizerEnabled(Fuzzer)
}
@ -756,6 +780,8 @@ func (sanitize *sanitize) SetSanitizer(t SanitizerType, b bool) {
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 @@ func sanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) {
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")
}

View File

@ -236,6 +236,10 @@ func (test *testDecorator) gtest() bool {
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

View File

@ -445,6 +445,14 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string {
stl: "none",
system_shared_libs: [],
}
cc_library_static {
name: "note_memtag_heap_async",
}
cc_library_static {
name: "note_memtag_heap_sync",
}
`
supportLinuxBionic := false