From 379de2fab01283c27a04404293a6ae06b00aac4b Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Wed, 19 Dec 2018 02:47:14 +0900 Subject: [PATCH] APEXes can be sanitized This change first introduces the interface "Sanitizeable" that module types other than cc.Module can use to be handled by the sanitizer mutator. APEX module, by implementing the interface, gets sanitizer variants. In doing so, sanitizer.go is refactored so that modules have explicit dependencies to the runtime sanitizer libraries. This allows the runtime library to be packaged into the APEX when required. This also completes the dependency graph; updating the prebuilt sanitizer runtime will trigger rebuilding of modules using the runtime. Bug: 120894259 Bug: 121038155 Test: SANITIZE_TARGET=hwaddress m apex.test Test: TARGET_FLATTEN_APEX=true SANITIZE_TARGET=address m Change-Id: Ia91576ff48cda3c996350308b75bf83fcf7c23d7 --- apex/apex.go | 8 ++ cc/cc.go | 21 ++-- cc/prebuilt.go | 8 ++ cc/sanitize.go | 295 ++++++++++++++++++++++++++++--------------------- 4 files changed, 197 insertions(+), 135 deletions(-) diff --git a/apex/apex.go b/apex/apex.go index e711c8bb2..62698681b 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -482,6 +482,11 @@ func (a *apexBundle) getImageVariation(config android.DeviceConfig) string { } } +func (a *apexBundle) IsSanitizerEnabled() bool { + // APEX can be mutated for sanitizers + return true +} + func getCopyManifestForNativeLibrary(cc *cc.Module) (fileToCopy android.Path, dirInApex string) { // Decide the APEX-local directory by the multilib of the library // In the future, we may query this to the module. @@ -903,6 +908,9 @@ func (a *apexBundle) androidMkForType(apexType apexPackaging) android.AndroidMkD fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)") for _, fi := range a.filesInfo { + if cc, ok := fi.module.(*cc.Module); ok && cc.Properties.HideFromMake { + continue + } fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)") fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir) fmt.Fprintln(w, "LOCAL_MODULE :=", fi.moduleName) diff --git a/cc/cc.go b/cc/cc.go index 85e3a6718..4717b726d 100644 --- a/cc/cc.go +++ b/cc/cc.go @@ -60,6 +60,7 @@ func init() { ctx.BottomUp("tsan", sanitizerMutator(tsan)).Parallel() ctx.TopDown("sanitize_runtime_deps", sanitizerRuntimeDepsMutator) + ctx.BottomUp("sanitize_runtime", sanitizerRuntimeMutator).Parallel() ctx.BottomUp("coverage", coverageLinkingMutator).Parallel() ctx.TopDown("vndk_deps", sabiDepsMutator) @@ -524,6 +525,8 @@ func (c *Module) onlyInRecovery() bool { func (c *Module) IsStubs() bool { if library, ok := c.linker.(*libraryDecorator); ok { return library.buildStubs() + } else if _, ok := c.linker.(*llndkStubDecorator); ok { + return true } return false } @@ -569,12 +572,7 @@ func (ctx *moduleContextImpl) static() bool { } func (ctx *moduleContextImpl) staticBinary() bool { - if static, ok := ctx.mod.linker.(interface { - staticBinary() bool - }); ok { - return static.staticBinary() - } - return false + return ctx.mod.staticBinary() } func (ctx *moduleContextImpl) useSdk() bool { @@ -891,7 +889,7 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { } } -func (c *Module) toolchain(ctx BaseModuleContext) config.Toolchain { +func (c *Module) toolchain(ctx android.BaseContext) config.Toolchain { if c.cachedToolchain == nil { c.cachedToolchain = config.FindToolchain(ctx.Os(), ctx.Arch()) } @@ -1708,6 +1706,15 @@ func (c *Module) static() bool { return false } +func (c *Module) staticBinary() bool { + if static, ok := c.linker.(interface { + staticBinary() bool + }); ok { + return static.staticBinary() + } + return false +} + func (c *Module) getMakeLinkType() string { if c.useVndk() { if inList(c.Name(), vndkCoreLibraries) || inList(c.Name(), vndkSpLibraries) || inList(c.Name(), llndkLibraries) { diff --git a/cc/prebuilt.go b/cc/prebuilt.go index 47994a8ca..ffeeb697b 100644 --- a/cc/prebuilt.go +++ b/cc/prebuilt.go @@ -103,6 +103,10 @@ func (p *prebuiltLibraryLinker) link(ctx ModuleContext, return nil } +func (p *prebuiltLibraryLinker) shared() bool { + return p.libraryDecorator.shared() +} + func prebuiltSharedLibraryFactory() android.Module { module, _ := NewPrebuiltSharedLibrary(android.HostAndDeviceSupported) return module.Init() @@ -121,6 +125,10 @@ func NewPrebuiltSharedLibrary(hod android.HostOrDeviceSupported) (*Module, *libr module.AddProperties(&prebuilt.properties) android.InitPrebuiltModule(module, &prebuilt.properties.Srcs) + + // Prebuilt libraries can be included in APEXes + android.InitApexModule(module) + return module, library } diff --git a/cc/sanitize.go b/cc/sanitize.go index 8d33de53d..d19e54a34 100644 --- a/cc/sanitize.go +++ b/cc/sanitize.go @@ -16,7 +16,6 @@ package cc import ( "fmt" - "io" "sort" "strings" "sync" @@ -138,18 +137,17 @@ type SanitizeProperties struct { Blacklist *string } `android:"arch_variant"` - SanitizerEnabled bool `blueprint:"mutated"` - SanitizeDep bool `blueprint:"mutated"` - MinimalRuntimeDep bool `blueprint:"mutated"` - UbsanRuntimeDep bool `blueprint:"mutated"` - InSanitizerDir bool `blueprint:"mutated"` + SanitizerEnabled bool `blueprint:"mutated"` + SanitizeDep bool `blueprint:"mutated"` + MinimalRuntimeDep bool `blueprint:"mutated"` + UbsanRuntimeDep bool `blueprint:"mutated"` + InSanitizerDir bool `blueprint:"mutated"` + Sanitizers []string `blueprint:"mutated"` + DiagSanitizers []string `blueprint:"mutated"` } type sanitize struct { Properties SanitizeProperties - - runtimeLibrary string - androidMkRuntimeLibrary string } func init() { @@ -405,46 +403,6 @@ func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags) Flags { return flags } - var sanitizers []string - var diagSanitizers []string - - if Bool(sanitize.Properties.Sanitize.All_undefined) { - sanitizers = append(sanitizers, "undefined") - } else { - if Bool(sanitize.Properties.Sanitize.Undefined) { - sanitizers = append(sanitizers, - "bool", - "integer-divide-by-zero", - "return", - "returns-nonnull-attribute", - "shift-exponent", - "unreachable", - "vla-bound", - // TODO(danalbert): The following checks currently have compiler performance issues. - //"alignment", - //"bounds", - //"enum", - //"float-cast-overflow", - //"float-divide-by-zero", - //"nonnull-attribute", - //"null", - //"shift-base", - //"signed-integer-overflow", - // TODO(danalbert): Fix UB in libc++'s __tree so we can turn this on. - // https://llvm.org/PR19302 - // http://reviews.llvm.org/D6974 - // "object-size", - ) - } - sanitizers = append(sanitizers, sanitize.Properties.Sanitize.Misc_undefined...) - } - - if Bool(sanitize.Properties.Sanitize.Diag.Undefined) { - diagSanitizers = append(diagSanitizers, "undefined") - } - - diagSanitizers = append(diagSanitizers, sanitize.Properties.Sanitize.Diag.Misc_undefined...) - if Bool(sanitize.Properties.Sanitize.Address) { if ctx.Arch().ArchType == android.Arm { // Frame pointer based unwinder in ASan requires ARM frame setup. @@ -465,34 +423,22 @@ func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags) Flags { flags.DynamicLinker += "64" } } - sanitizers = append(sanitizers, "address") - diagSanitizers = append(diagSanitizers, "address") } if Bool(sanitize.Properties.Sanitize.Hwaddress) { flags.CFlags = append(flags.CFlags, hwasanCflags...) - sanitizers = append(sanitizers, "hwaddress") - } - - if Bool(sanitize.Properties.Sanitize.Thread) { - sanitizers = append(sanitizers, "thread") } if Bool(sanitize.Properties.Sanitize.Coverage) { flags.CFlags = append(flags.CFlags, "-fsanitize-coverage=trace-pc-guard,indirect-calls,trace-cmp") } - if Bool(sanitize.Properties.Sanitize.Safestack) { - sanitizers = append(sanitizers, "safe-stack") - } - if Bool(sanitize.Properties.Sanitize.Cfi) { if ctx.Arch().ArchType == android.Arm { // __cfi_check needs to be built as Thumb (see the code in linker_cfi.cpp). LLVM is not set up // to do this on a function basis, so force Thumb on the entire module. flags.RequiredInstructionSet = "thumb" } - sanitizers = append(sanitizers, "cfi") flags.CFlags = append(flags.CFlags, cfiCflags...) flags.AsFlags = append(flags.AsFlags, cfiAsflags...) @@ -502,9 +448,6 @@ func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags) Flags { flags.CFlags = append(flags.CFlags, "-fvisibility=default") } flags.LdFlags = append(flags.LdFlags, cfiLdflags...) - if Bool(sanitize.Properties.Sanitize.Diag.Cfi) { - diagSanitizers = append(diagSanitizers, "cfi") - } if ctx.staticBinary() { _, flags.CFlags = removeFromList("-fsanitize-cfi-cross-dso", flags.CFlags) @@ -513,25 +456,11 @@ func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags) Flags { } if Bool(sanitize.Properties.Sanitize.Integer_overflow) { - sanitizers = append(sanitizers, "unsigned-integer-overflow") - sanitizers = append(sanitizers, "signed-integer-overflow") flags.CFlags = append(flags.CFlags, intOverflowCflags...) - if Bool(sanitize.Properties.Sanitize.Diag.Integer_overflow) { - diagSanitizers = append(diagSanitizers, "unsigned-integer-overflow") - diagSanitizers = append(diagSanitizers, "signed-integer-overflow") - } } - if Bool(sanitize.Properties.Sanitize.Scudo) { - sanitizers = append(sanitizers, "scudo") - } - - if Bool(sanitize.Properties.Sanitize.Scs) { - sanitizers = append(sanitizers, "shadow-call-stack") - } - - if len(sanitizers) > 0 { - sanitizeArg := "-fsanitize=" + strings.Join(sanitizers, ",") + if len(sanitize.Properties.Sanitizers) > 0 { + sanitizeArg := "-fsanitize=" + strings.Join(sanitize.Properties.Sanitizers, ",") flags.CFlags = append(flags.CFlags, sanitizeArg) flags.AsFlags = append(flags.AsFlags, sanitizeArg) @@ -556,8 +485,8 @@ func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags) Flags { } } - if len(diagSanitizers) > 0 { - flags.CFlags = append(flags.CFlags, "-fno-sanitize-trap="+strings.Join(diagSanitizers, ",")) + if len(sanitize.Properties.DiagSanitizers) > 0 { + flags.CFlags = append(flags.CFlags, "-fno-sanitize-trap="+strings.Join(sanitize.Properties.DiagSanitizers, ",")) } // FIXME: enable RTTI if diag + (cfi or vptr) @@ -571,46 +500,6 @@ func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags) Flags { strings.Join(sanitize.Properties.Sanitize.Diag.No_recover, ",")) } - // Link a runtime library if needed. - runtimeLibrary := "" - if Bool(sanitize.Properties.Sanitize.Address) { - runtimeLibrary = config.AddressSanitizerRuntimeLibrary(ctx.toolchain()) - } else if Bool(sanitize.Properties.Sanitize.Hwaddress) { - runtimeLibrary = config.HWAddressSanitizerRuntimeLibrary(ctx.toolchain()) - } else if Bool(sanitize.Properties.Sanitize.Thread) { - runtimeLibrary = config.ThreadSanitizerRuntimeLibrary(ctx.toolchain()) - } else if Bool(sanitize.Properties.Sanitize.Scudo) { - if len(diagSanitizers) == 0 && !sanitize.Properties.UbsanRuntimeDep { - runtimeLibrary = config.ScudoMinimalRuntimeLibrary(ctx.toolchain()) - } else { - runtimeLibrary = config.ScudoRuntimeLibrary(ctx.toolchain()) - } - } else if len(diagSanitizers) > 0 || sanitize.Properties.UbsanRuntimeDep { - runtimeLibrary = config.UndefinedBehaviorSanitizerRuntimeLibrary(ctx.toolchain()) - } - - if runtimeLibrary != "" { - runtimeLibraryPath := "${config.ClangAsanLibDir}/" + runtimeLibrary - if !ctx.static() { - runtimeLibraryPath = runtimeLibraryPath + ctx.toolchain().ShlibSuffix() - } else { - runtimeLibraryPath = runtimeLibraryPath + ".a" - } - - // ASan runtime library must be the first in the link order. - flags.libFlags = append([]string{runtimeLibraryPath}, flags.libFlags...) - sanitize.runtimeLibrary = runtimeLibrary - - // When linking against VNDK, use the vendor variant of the runtime lib - if ctx.useVndk() { - sanitize.androidMkRuntimeLibrary = sanitize.runtimeLibrary + vendorSuffix - } else if ctx.inRecovery() { - sanitize.androidMkRuntimeLibrary = sanitize.runtimeLibrary + recoverySuffix - } else { - sanitize.androidMkRuntimeLibrary = sanitize.runtimeLibrary - } - } - blacklist := android.OptionalPathForModuleSrc(ctx, sanitize.Properties.Sanitize.Blacklist) if blacklist.Valid() { flags.CFlags = append(flags.CFlags, "-fsanitize-blacklist="+blacklist.String()) @@ -621,12 +510,6 @@ func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags) Flags { } func (sanitize *sanitize) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { - ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) { - if sanitize.androidMkRuntimeLibrary != "" { - fmt.Fprintln(w, "LOCAL_SHARED_LIBRARIES += "+sanitize.androidMkRuntimeLibrary) - } - }) - // Add a suffix for CFI-enabled static libraries to allow surfacing both to make without a // name conflict. if ret.Class == "STATIC_LIBRARIES" && Bool(sanitize.Properties.Sanitize.Cfi) { @@ -782,6 +665,159 @@ func sanitizerRuntimeDepsMutator(mctx android.TopDownMutatorContext) { } } +// Add the dependency to the runtime library for each of the sanitizer variants +func sanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) { + if mctx.Os() != android.Android { + return + } + if c, ok := mctx.Module().(*Module); ok && c.sanitize != nil { + var sanitizers []string + var diagSanitizers []string + + if Bool(c.sanitize.Properties.Sanitize.All_undefined) { + sanitizers = append(sanitizers, "undefined") + } else { + if Bool(c.sanitize.Properties.Sanitize.Undefined) { + sanitizers = append(sanitizers, + "bool", + "integer-divide-by-zero", + "return", + "returns-nonnull-attribute", + "shift-exponent", + "unreachable", + "vla-bound", + // TODO(danalbert): The following checks currently have compiler performance issues. + //"alignment", + //"bounds", + //"enum", + //"float-cast-overflow", + //"float-divide-by-zero", + //"nonnull-attribute", + //"null", + //"shift-base", + //"signed-integer-overflow", + // TODO(danalbert): Fix UB in libc++'s __tree so we can turn this on. + // https://llvm.org/PR19302 + // http://reviews.llvm.org/D6974 + // "object-size", + ) + } + sanitizers = append(sanitizers, c.sanitize.Properties.Sanitize.Misc_undefined...) + } + + if Bool(c.sanitize.Properties.Sanitize.Diag.Undefined) { + diagSanitizers = append(diagSanitizers, "undefined") + } + + diagSanitizers = append(diagSanitizers, c.sanitize.Properties.Sanitize.Diag.Misc_undefined...) + + if Bool(c.sanitize.Properties.Sanitize.Address) { + sanitizers = append(sanitizers, "address") + diagSanitizers = append(diagSanitizers, "address") + } + + if Bool(c.sanitize.Properties.Sanitize.Hwaddress) { + sanitizers = append(sanitizers, "hwaddress") + } + + if Bool(c.sanitize.Properties.Sanitize.Thread) { + sanitizers = append(sanitizers, "thread") + } + + if Bool(c.sanitize.Properties.Sanitize.Safestack) { + sanitizers = append(sanitizers, "safe-stack") + } + + if Bool(c.sanitize.Properties.Sanitize.Cfi) { + sanitizers = append(sanitizers, "cfi") + + if Bool(c.sanitize.Properties.Sanitize.Diag.Cfi) { + diagSanitizers = append(diagSanitizers, "cfi") + } + } + + if Bool(c.sanitize.Properties.Sanitize.Integer_overflow) { + sanitizers = append(sanitizers, "unsigned-integer-overflow") + sanitizers = append(sanitizers, "signed-integer-overflow") + if Bool(c.sanitize.Properties.Sanitize.Diag.Integer_overflow) { + diagSanitizers = append(diagSanitizers, "unsigned-integer-overflow") + diagSanitizers = append(diagSanitizers, "signed-integer-overflow") + } + } + + if Bool(c.sanitize.Properties.Sanitize.Scudo) { + sanitizers = append(sanitizers, "scudo") + } + + if Bool(c.sanitize.Properties.Sanitize.Scs) { + sanitizers = append(sanitizers, "shadow-call-stack") + } + + // Save the list of sanitizers. These will be used again when generating + // the build rules (for Cflags, etc.) + c.sanitize.Properties.Sanitizers = sanitizers + c.sanitize.Properties.DiagSanitizers = diagSanitizers + + // Determine the runtime library required + runtimeLibrary := "" + toolchain := c.toolchain(mctx) + if Bool(c.sanitize.Properties.Sanitize.Address) { + runtimeLibrary = config.AddressSanitizerRuntimeLibrary(toolchain) + } else if Bool(c.sanitize.Properties.Sanitize.Hwaddress) { + if c.staticBinary() { + runtimeLibrary = config.HWAddressSanitizerStaticLibrary(toolchain) + } else { + runtimeLibrary = config.HWAddressSanitizerRuntimeLibrary(toolchain) + } + } else if Bool(c.sanitize.Properties.Sanitize.Thread) { + runtimeLibrary = config.ThreadSanitizerRuntimeLibrary(toolchain) + } else if Bool(c.sanitize.Properties.Sanitize.Scudo) { + if len(diagSanitizers) == 0 && !c.sanitize.Properties.UbsanRuntimeDep { + runtimeLibrary = config.ScudoMinimalRuntimeLibrary(toolchain) + } else { + runtimeLibrary = config.ScudoRuntimeLibrary(toolchain) + } + } else if len(diagSanitizers) > 0 || c.sanitize.Properties.UbsanRuntimeDep { + runtimeLibrary = config.UndefinedBehaviorSanitizerRuntimeLibrary(toolchain) + } + + if mctx.Device() && runtimeLibrary != "" { + if inList(runtimeLibrary, llndkLibraries) && !c.static() { + runtimeLibrary = runtimeLibrary + llndkLibrarySuffix + } + + // Adding dependency to the runtime library. We are using *FarVariation* + // because the runtime libraries themselves are not mutated by sanitizer + // mutators and thus don't have sanitizer variants whereas this module + // has been already mutated. + // + // Note that by adding dependency with {static|shared}DepTag, the lib is + // added to libFlags and LOCAL_SHARED_LIBRARIES by cc.Module + if c.staticBinary() { + // static executable gets static runtime libs + mctx.AddFarVariationDependencies([]blueprint.Variation{ + {Mutator: "link", Variation: "static"}, + {Mutator: "arch", Variation: mctx.Target().String()}, + }, staticDepTag, runtimeLibrary) + } else if !c.static() { + // dynamic executable andshared libs get shared runtime libs + mctx.AddFarVariationDependencies([]blueprint.Variation{ + {Mutator: "link", Variation: "shared"}, + {Mutator: "arch", Variation: mctx.Target().String()}, + }, sharedDepTag, runtimeLibrary) + } + // static lib does not have dependency to the runtime library. The + // dependency will be added to the executables or shared libs using + // the static lib. + } + } +} + +type Sanitizeable interface { + android.Module + IsSanitizerEnabled() bool +} + // Create sanitized variants for modules that need them func sanitizerMutator(t sanitizerType) func(android.BottomUpMutatorContext) { return func(mctx android.BottomUpMutatorContext) { @@ -883,6 +919,9 @@ func sanitizerMutator(t sanitizerType) func(android.BottomUpMutatorContext) { } } c.sanitize.Properties.SanitizeDep = false + } else if sanitizeable, ok := mctx.Module().(Sanitizeable); ok && sanitizeable.IsSanitizerEnabled() { + // APEX modules fall here + mctx.CreateVariations(t.String()) } } }