1// Copyright 2016 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package cc 16 17import ( 18 "fmt" 19 "sort" 20 "strings" 21 "sync" 22 23 "github.com/google/blueprint" 24 25 "android/soong/android" 26 "android/soong/cc/config" 27) 28 29var ( 30 // Any C flags added by sanitizer which libTooling tools may not 31 // understand also need to be added to ClangLibToolingUnknownCflags in 32 // cc/config/clang.go 33 34 asanCflags = []string{"-fno-omit-frame-pointer"} 35 asanLdflags = []string{"-Wl,-u,__asan_preinit"} 36 asanLibs = []string{"libasan"} 37 38 // TODO(pcc): Stop passing -hwasan-allow-ifunc here once it has been made 39 // the default. 40 hwasanCflags = []string{"-fno-omit-frame-pointer", "-Wno-frame-larger-than=", 41 "-mllvm", "-hwasan-create-frame-descriptions=0", 42 "-mllvm", "-hwasan-allow-ifunc", 43 "-fsanitize-hwaddress-abi=platform"} 44 45 cfiCflags = []string{"-flto", "-fsanitize-cfi-cross-dso", 46 "-fsanitize-blacklist=external/compiler-rt/lib/cfi/cfi_blacklist.txt"} 47 // -flto and -fvisibility are required by clang when -fsanitize=cfi is 48 // used, but have no effect on assembly files 49 cfiAsflags = []string{"-flto", "-fvisibility=default"} 50 cfiLdflags = []string{"-flto", "-fsanitize-cfi-cross-dso", "-fsanitize=cfi", 51 "-Wl,-plugin-opt,O1"} 52 cfiExportsMapPath = "build/soong/cc/config/cfi_exports.map" 53 cfiStaticLibsMutex sync.Mutex 54 hwasanStaticLibsMutex sync.Mutex 55 56 intOverflowCflags = []string{"-fsanitize-blacklist=build/soong/cc/config/integer_overflow_blacklist.txt"} 57 58 minimalRuntimeFlags = []string{"-fsanitize-minimal-runtime", "-fno-sanitize-trap=integer,undefined", 59 "-fno-sanitize-recover=integer,undefined"} 60 hwasanGlobalOptions = []string{"heap_history_size=1023", "stack_history_size=512", 61 "export_memory_stats=0", "max_malloc_fill_size=0"} 62) 63 64type sanitizerType int 65 66func boolPtr(v bool) *bool { 67 if v { 68 return &v 69 } else { 70 return nil 71 } 72} 73 74const ( 75 asan sanitizerType = iota + 1 76 hwasan 77 tsan 78 intOverflow 79 cfi 80 scs 81) 82 83// Name of the sanitizer variation for this sanitizer type 84func (t sanitizerType) variationName() string { 85 switch t { 86 case asan: 87 return "asan" 88 case hwasan: 89 return "hwasan" 90 case tsan: 91 return "tsan" 92 case intOverflow: 93 return "intOverflow" 94 case cfi: 95 return "cfi" 96 case scs: 97 return "scs" 98 default: 99 panic(fmt.Errorf("unknown sanitizerType %d", t)) 100 } 101} 102 103// This is the sanitizer names in SANITIZE_[TARGET|HOST] 104func (t sanitizerType) name() string { 105 switch t { 106 case asan: 107 return "address" 108 case hwasan: 109 return "hwaddress" 110 case tsan: 111 return "thread" 112 case intOverflow: 113 return "integer_overflow" 114 case cfi: 115 return "cfi" 116 case scs: 117 return "shadow-call-stack" 118 default: 119 panic(fmt.Errorf("unknown sanitizerType %d", t)) 120 } 121} 122 123type SanitizeProperties struct { 124 // enable AddressSanitizer, ThreadSanitizer, or UndefinedBehaviorSanitizer 125 Sanitize struct { 126 Never *bool `android:"arch_variant"` 127 128 // main sanitizers 129 Address *bool `android:"arch_variant"` 130 Thread *bool `android:"arch_variant"` 131 Hwaddress *bool `android:"arch_variant"` 132 133 // local sanitizers 134 Undefined *bool `android:"arch_variant"` 135 All_undefined *bool `android:"arch_variant"` 136 Misc_undefined []string `android:"arch_variant"` 137 Coverage *bool `android:"arch_variant"` 138 Safestack *bool `android:"arch_variant"` 139 Cfi *bool `android:"arch_variant"` 140 Integer_overflow *bool `android:"arch_variant"` 141 Scudo *bool `android:"arch_variant"` 142 Scs *bool `android:"arch_variant"` 143 144 // Sanitizers to run in the diagnostic mode (as opposed to the release mode). 145 // Replaces abort() on error with a human-readable error message. 146 // Address and Thread sanitizers always run in diagnostic mode. 147 Diag struct { 148 Undefined *bool `android:"arch_variant"` 149 Cfi *bool `android:"arch_variant"` 150 Integer_overflow *bool `android:"arch_variant"` 151 Misc_undefined []string `android:"arch_variant"` 152 No_recover []string 153 } 154 155 // value to pass to -fsanitize-recover= 156 Recover []string 157 158 // value to pass to -fsanitize-blacklist 159 Blacklist *string 160 } `android:"arch_variant"` 161 162 SanitizerEnabled bool `blueprint:"mutated"` 163 SanitizeDep bool `blueprint:"mutated"` 164 MinimalRuntimeDep bool `blueprint:"mutated"` 165 UbsanRuntimeDep bool `blueprint:"mutated"` 166 InSanitizerDir bool `blueprint:"mutated"` 167 Sanitizers []string `blueprint:"mutated"` 168 DiagSanitizers []string `blueprint:"mutated"` 169} 170 171type sanitize struct { 172 Properties SanitizeProperties 173} 174 175func init() { 176 android.RegisterMakeVarsProvider(pctx, cfiMakeVarsProvider) 177 android.RegisterMakeVarsProvider(pctx, hwasanMakeVarsProvider) 178} 179 180func (sanitize *sanitize) props() []interface{} { 181 return []interface{}{&sanitize.Properties} 182} 183 184func (sanitize *sanitize) begin(ctx BaseModuleContext) { 185 s := &sanitize.Properties.Sanitize 186 187 // Don't apply sanitizers to NDK code. 188 if ctx.useSdk() { 189 s.Never = BoolPtr(true) 190 } 191 192 // Sanitizers do not work on Fuchsia yet. 193 if ctx.Fuchsia() { 194 s.Never = BoolPtr(true) 195 } 196 197 // Never always wins. 198 if Bool(s.Never) { 199 return 200 } 201 202 var globalSanitizers []string 203 var globalSanitizersDiag []string 204 205 if ctx.Host() { 206 if !ctx.Windows() { 207 globalSanitizers = ctx.Config().SanitizeHost() 208 } 209 } else { 210 arches := ctx.Config().SanitizeDeviceArch() 211 if len(arches) == 0 || inList(ctx.Arch().ArchType.Name, arches) { 212 globalSanitizers = ctx.Config().SanitizeDevice() 213 globalSanitizersDiag = ctx.Config().SanitizeDeviceDiag() 214 } 215 } 216 217 if len(globalSanitizers) > 0 { 218 var found bool 219 if found, globalSanitizers = removeFromList("undefined", globalSanitizers); found && s.All_undefined == nil { 220 s.All_undefined = boolPtr(true) 221 } 222 223 if found, globalSanitizers = removeFromList("default-ub", globalSanitizers); found && s.Undefined == nil { 224 s.Undefined = boolPtr(true) 225 } 226 227 if found, globalSanitizers = removeFromList("address", globalSanitizers); found { 228 if s.Address == nil { 229 s.Address = boolPtr(true) 230 } else if *s.Address == false { 231 // Coverage w/o address is an error. If globalSanitizers includes both, and the module 232 // disables address, then disable coverage as well. 233 _, globalSanitizers = removeFromList("coverage", globalSanitizers) 234 } 235 } 236 237 if found, globalSanitizers = removeFromList("thread", globalSanitizers); found && s.Thread == nil { 238 s.Thread = boolPtr(true) 239 } 240 241 if found, globalSanitizers = removeFromList("coverage", globalSanitizers); found && s.Coverage == nil { 242 s.Coverage = boolPtr(true) 243 } 244 245 if found, globalSanitizers = removeFromList("safe-stack", globalSanitizers); found && s.Safestack == nil { 246 s.Safestack = boolPtr(true) 247 } 248 249 if found, globalSanitizers = removeFromList("cfi", globalSanitizers); found && s.Cfi == nil { 250 if !ctx.Config().CFIDisabledForPath(ctx.ModuleDir()) { 251 s.Cfi = boolPtr(true) 252 } 253 } 254 255 // Global integer_overflow builds do not support static libraries. 256 if found, globalSanitizers = removeFromList("integer_overflow", globalSanitizers); found && s.Integer_overflow == nil { 257 if !ctx.Config().IntegerOverflowDisabledForPath(ctx.ModuleDir()) && !ctx.static() { 258 s.Integer_overflow = boolPtr(true) 259 } 260 } 261 262 if found, globalSanitizers = removeFromList("scudo", globalSanitizers); found && s.Scudo == nil { 263 s.Scudo = boolPtr(true) 264 } 265 266 if found, globalSanitizers = removeFromList("hwaddress", globalSanitizers); found && s.Hwaddress == nil { 267 s.Hwaddress = boolPtr(true) 268 } 269 270 if len(globalSanitizers) > 0 { 271 ctx.ModuleErrorf("unknown global sanitizer option %s", globalSanitizers[0]) 272 } 273 274 // Global integer_overflow builds do not support static library diagnostics. 275 if found, globalSanitizersDiag = removeFromList("integer_overflow", globalSanitizersDiag); found && 276 s.Diag.Integer_overflow == nil && Bool(s.Integer_overflow) && !ctx.static() { 277 s.Diag.Integer_overflow = boolPtr(true) 278 } 279 280 if found, globalSanitizersDiag = removeFromList("cfi", globalSanitizersDiag); found && 281 s.Diag.Cfi == nil && Bool(s.Cfi) { 282 s.Diag.Cfi = boolPtr(true) 283 } 284 285 if len(globalSanitizersDiag) > 0 { 286 ctx.ModuleErrorf("unknown global sanitizer diagnostics option %s", globalSanitizersDiag[0]) 287 } 288 } 289 290 // Enable CFI for all components in the include paths (for Aarch64 only) 291 if s.Cfi == nil && ctx.Config().CFIEnabledForPath(ctx.ModuleDir()) && ctx.Arch().ArchType == android.Arm64 { 292 s.Cfi = boolPtr(true) 293 if inList("cfi", ctx.Config().SanitizeDeviceDiag()) { 294 s.Diag.Cfi = boolPtr(true) 295 } 296 } 297 298 // CFI needs gold linker, and mips toolchain does not have one. 299 if !ctx.Config().EnableCFI() || ctx.Arch().ArchType == android.Mips || ctx.Arch().ArchType == android.Mips64 { 300 s.Cfi = nil 301 s.Diag.Cfi = nil 302 } 303 304 // Also disable CFI for arm32 until b/35157333 is fixed. 305 if ctx.Arch().ArchType == android.Arm { 306 s.Cfi = nil 307 s.Diag.Cfi = nil 308 } 309 310 // HWASan requires AArch64 hardware feature (top-byte-ignore). 311 if ctx.Arch().ArchType != android.Arm64 { 312 s.Hwaddress = nil 313 } 314 315 // SCS is only implemented on AArch64. 316 if ctx.Arch().ArchType != android.Arm64 { 317 s.Scs = nil 318 } 319 320 // Also disable CFI if ASAN is enabled. 321 if Bool(s.Address) || Bool(s.Hwaddress) { 322 s.Cfi = nil 323 s.Diag.Cfi = nil 324 } 325 326 // Disable sanitizers that depend on the UBSan runtime for host builds. 327 if ctx.Host() { 328 s.Cfi = nil 329 s.Diag.Cfi = nil 330 s.Misc_undefined = nil 331 s.Undefined = nil 332 s.All_undefined = nil 333 s.Integer_overflow = nil 334 } 335 336 // Also disable CFI for VNDK variants of components 337 if ctx.isVndk() && ctx.useVndk() { 338 s.Cfi = nil 339 s.Diag.Cfi = nil 340 } 341 342 // HWASan ramdisk (which is built from recovery) goes over some bootloader limit. 343 // Keep libc instrumented so that recovery can run hwasan-instrumented code if necessary. 344 if ctx.inRecovery() && !strings.HasPrefix(ctx.ModuleDir(), "bionic/libc") { 345 s.Hwaddress = nil 346 } 347 348 if ctx.staticBinary() { 349 s.Address = nil 350 s.Coverage = nil 351 s.Thread = nil 352 } 353 354 if Bool(s.All_undefined) { 355 s.Undefined = nil 356 } 357 358 if !ctx.toolchain().Is64Bit() { 359 // TSAN and SafeStack are not supported on 32-bit architectures 360 s.Thread = nil 361 s.Safestack = nil 362 // TODO(ccross): error for compile_multilib = "32"? 363 } 364 365 if ctx.Os() != android.Windows && (Bool(s.All_undefined) || Bool(s.Undefined) || Bool(s.Address) || Bool(s.Thread) || 366 Bool(s.Coverage) || Bool(s.Safestack) || Bool(s.Cfi) || Bool(s.Integer_overflow) || len(s.Misc_undefined) > 0 || 367 Bool(s.Scudo) || Bool(s.Hwaddress) || Bool(s.Scs)) { 368 sanitize.Properties.SanitizerEnabled = true 369 } 370 371 // Disable Scudo if ASan or TSan is enabled, or if it's disabled globally. 372 if Bool(s.Address) || Bool(s.Thread) || Bool(s.Hwaddress) || ctx.Config().DisableScudo() { 373 s.Scudo = nil 374 } 375 376 if Bool(s.Hwaddress) { 377 s.Address = nil 378 s.Thread = nil 379 } 380 381 if Bool(s.Coverage) { 382 if !Bool(s.Address) { 383 ctx.ModuleErrorf(`Use of "coverage" also requires "address"`) 384 } 385 } 386} 387 388func (sanitize *sanitize) deps(ctx BaseModuleContext, deps Deps) Deps { 389 if !sanitize.Properties.SanitizerEnabled { // || c.static() { 390 return deps 391 } 392 393 if ctx.Device() { 394 if Bool(sanitize.Properties.Sanitize.Address) { 395 deps.StaticLibs = append(deps.StaticLibs, asanLibs...) 396 // Compiling asan and having libc_scudo in the same 397 // executable will cause the executable to crash. 398 // Remove libc_scudo since it is only used to override 399 // allocation functions which asan already overrides. 400 _, deps.SharedLibs = removeFromList("libc_scudo", deps.SharedLibs) 401 } 402 } 403 404 return deps 405} 406 407func toDisableImplicitIntegerChange(flags []string) bool { 408 // Returns true if any flag is fsanitize*integer, and there is 409 // no explicit flag about sanitize=implicit-integer-sign-change. 410 for _, f := range flags { 411 if strings.Contains(f, "sanitize=implicit-integer-sign-change") { 412 return false 413 } 414 } 415 for _, f := range flags { 416 if strings.HasPrefix(f, "-fsanitize") && strings.Contains(f, "integer") { 417 return true 418 } 419 } 420 return false 421} 422 423func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags) Flags { 424 minimalRuntimeLib := config.UndefinedBehaviorSanitizerMinimalRuntimeLibrary(ctx.toolchain()) + ".a" 425 minimalRuntimePath := "${config.ClangAsanLibDir}/" + minimalRuntimeLib 426 427 if ctx.Device() && sanitize.Properties.MinimalRuntimeDep { 428 flags.LdFlags = append(flags.LdFlags, minimalRuntimePath) 429 flags.LdFlags = append(flags.LdFlags, "-Wl,--exclude-libs,"+minimalRuntimeLib) 430 } 431 if !sanitize.Properties.SanitizerEnabled && !sanitize.Properties.UbsanRuntimeDep { 432 return flags 433 } 434 435 if Bool(sanitize.Properties.Sanitize.Address) { 436 if ctx.Arch().ArchType == android.Arm { 437 // Frame pointer based unwinder in ASan requires ARM frame setup. 438 // TODO: put in flags? 439 flags.RequiredInstructionSet = "arm" 440 } 441 flags.CFlags = append(flags.CFlags, asanCflags...) 442 flags.LdFlags = append(flags.LdFlags, asanLdflags...) 443 444 if ctx.Host() { 445 // -nodefaultlibs (provided with libc++) prevents the driver from linking 446 // libraries needed with -fsanitize=address. http://b/18650275 (WAI) 447 flags.LdFlags = append(flags.LdFlags, "-Wl,--no-as-needed") 448 } else { 449 flags.CFlags = append(flags.CFlags, "-mllvm", "-asan-globals=0") 450 if ctx.bootstrap() { 451 flags.DynamicLinker = "/system/bin/bootstrap/linker_asan" 452 } else { 453 flags.DynamicLinker = "/system/bin/linker_asan" 454 } 455 if flags.Toolchain.Is64Bit() { 456 flags.DynamicLinker += "64" 457 } 458 } 459 } 460 461 if Bool(sanitize.Properties.Sanitize.Hwaddress) { 462 flags.CFlags = append(flags.CFlags, hwasanCflags...) 463 } 464 465 if Bool(sanitize.Properties.Sanitize.Coverage) { 466 flags.CFlags = append(flags.CFlags, "-fsanitize-coverage=trace-pc-guard,indirect-calls,trace-cmp") 467 } 468 469 if Bool(sanitize.Properties.Sanitize.Cfi) { 470 if ctx.Arch().ArchType == android.Arm { 471 // __cfi_check needs to be built as Thumb (see the code in linker_cfi.cpp). LLVM is not set up 472 // to do this on a function basis, so force Thumb on the entire module. 473 flags.RequiredInstructionSet = "thumb" 474 } 475 476 flags.CFlags = append(flags.CFlags, cfiCflags...) 477 flags.AsFlags = append(flags.AsFlags, cfiAsflags...) 478 // Only append the default visibility flag if -fvisibility has not already been set 479 // to hidden. 480 if !inList("-fvisibility=hidden", flags.CFlags) { 481 flags.CFlags = append(flags.CFlags, "-fvisibility=default") 482 } 483 flags.LdFlags = append(flags.LdFlags, cfiLdflags...) 484 485 if ctx.staticBinary() { 486 _, flags.CFlags = removeFromList("-fsanitize-cfi-cross-dso", flags.CFlags) 487 _, flags.LdFlags = removeFromList("-fsanitize-cfi-cross-dso", flags.LdFlags) 488 } 489 } 490 491 if Bool(sanitize.Properties.Sanitize.Integer_overflow) { 492 flags.CFlags = append(flags.CFlags, intOverflowCflags...) 493 } 494 495 if len(sanitize.Properties.Sanitizers) > 0 { 496 sanitizeArg := "-fsanitize=" + strings.Join(sanitize.Properties.Sanitizers, ",") 497 498 flags.CFlags = append(flags.CFlags, sanitizeArg) 499 flags.AsFlags = append(flags.AsFlags, sanitizeArg) 500 if ctx.Host() { 501 flags.CFlags = append(flags.CFlags, "-fno-sanitize-recover=all") 502 flags.LdFlags = append(flags.LdFlags, sanitizeArg) 503 // Host sanitizers only link symbols in the final executable, so 504 // there will always be undefined symbols in intermediate libraries. 505 _, flags.LdFlags = removeFromList("-Wl,--no-undefined", flags.LdFlags) 506 } else { 507 flags.CFlags = append(flags.CFlags, "-fsanitize-trap=all", "-ftrap-function=abort") 508 509 if enableMinimalRuntime(sanitize) { 510 flags.CFlags = append(flags.CFlags, strings.Join(minimalRuntimeFlags, " ")) 511 flags.libFlags = append([]string{minimalRuntimePath}, flags.libFlags...) 512 flags.LdFlags = append(flags.LdFlags, "-Wl,--exclude-libs,"+minimalRuntimeLib) 513 } 514 } 515 // http://b/119329758, Android core does not boot up with this sanitizer yet. 516 if toDisableImplicitIntegerChange(flags.CFlags) { 517 flags.CFlags = append(flags.CFlags, "-fno-sanitize=implicit-integer-sign-change") 518 } 519 } 520 521 if len(sanitize.Properties.DiagSanitizers) > 0 { 522 flags.CFlags = append(flags.CFlags, "-fno-sanitize-trap="+strings.Join(sanitize.Properties.DiagSanitizers, ",")) 523 } 524 // FIXME: enable RTTI if diag + (cfi or vptr) 525 526 if sanitize.Properties.Sanitize.Recover != nil { 527 flags.CFlags = append(flags.CFlags, "-fsanitize-recover="+ 528 strings.Join(sanitize.Properties.Sanitize.Recover, ",")) 529 } 530 531 if sanitize.Properties.Sanitize.Diag.No_recover != nil { 532 flags.CFlags = append(flags.CFlags, "-fno-sanitize-recover="+ 533 strings.Join(sanitize.Properties.Sanitize.Diag.No_recover, ",")) 534 } 535 536 blacklist := android.OptionalPathForModuleSrc(ctx, sanitize.Properties.Sanitize.Blacklist) 537 if blacklist.Valid() { 538 flags.CFlags = append(flags.CFlags, "-fsanitize-blacklist="+blacklist.String()) 539 flags.CFlagsDeps = append(flags.CFlagsDeps, blacklist.Path()) 540 } 541 542 return flags 543} 544 545func (sanitize *sanitize) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { 546 // Add a suffix for CFI-enabled static libraries to allow surfacing both to make without a 547 // name conflict. 548 if ret.Class == "STATIC_LIBRARIES" && Bool(sanitize.Properties.Sanitize.Cfi) { 549 ret.SubName += ".cfi" 550 } 551 if ret.Class == "STATIC_LIBRARIES" && Bool(sanitize.Properties.Sanitize.Hwaddress) { 552 ret.SubName += ".hwasan" 553 } 554 if ret.Class == "STATIC_LIBRARIES" && Bool(sanitize.Properties.Sanitize.Scs) { 555 ret.SubName += ".scs" 556 } 557} 558 559func (sanitize *sanitize) inSanitizerDir() bool { 560 return sanitize.Properties.InSanitizerDir 561} 562 563func (sanitize *sanitize) getSanitizerBoolPtr(t sanitizerType) *bool { 564 switch t { 565 case asan: 566 return sanitize.Properties.Sanitize.Address 567 case hwasan: 568 return sanitize.Properties.Sanitize.Hwaddress 569 case tsan: 570 return sanitize.Properties.Sanitize.Thread 571 case intOverflow: 572 return sanitize.Properties.Sanitize.Integer_overflow 573 case cfi: 574 return sanitize.Properties.Sanitize.Cfi 575 case scs: 576 return sanitize.Properties.Sanitize.Scs 577 default: 578 panic(fmt.Errorf("unknown sanitizerType %d", t)) 579 } 580} 581 582func (sanitize *sanitize) isUnsanitizedVariant() bool { 583 return !sanitize.isSanitizerEnabled(asan) && 584 !sanitize.isSanitizerEnabled(hwasan) && 585 !sanitize.isSanitizerEnabled(tsan) && 586 !sanitize.isSanitizerEnabled(cfi) && 587 !sanitize.isSanitizerEnabled(scs) 588} 589 590func (sanitize *sanitize) isVariantOnProductionDevice() bool { 591 return !sanitize.isSanitizerEnabled(asan) && 592 !sanitize.isSanitizerEnabled(hwasan) && 593 !sanitize.isSanitizerEnabled(tsan) 594} 595 596func (sanitize *sanitize) SetSanitizer(t sanitizerType, b bool) { 597 switch t { 598 case asan: 599 sanitize.Properties.Sanitize.Address = boolPtr(b) 600 if !b { 601 sanitize.Properties.Sanitize.Coverage = nil 602 } 603 case hwasan: 604 sanitize.Properties.Sanitize.Hwaddress = boolPtr(b) 605 case tsan: 606 sanitize.Properties.Sanitize.Thread = boolPtr(b) 607 case intOverflow: 608 sanitize.Properties.Sanitize.Integer_overflow = boolPtr(b) 609 case cfi: 610 sanitize.Properties.Sanitize.Cfi = boolPtr(b) 611 case scs: 612 sanitize.Properties.Sanitize.Scs = boolPtr(b) 613 default: 614 panic(fmt.Errorf("unknown sanitizerType %d", t)) 615 } 616 if b { 617 sanitize.Properties.SanitizerEnabled = true 618 } 619} 620 621// Check if the sanitizer is explicitly disabled (as opposed to nil by 622// virtue of not being set). 623func (sanitize *sanitize) isSanitizerExplicitlyDisabled(t sanitizerType) bool { 624 if sanitize == nil { 625 return false 626 } 627 628 sanitizerVal := sanitize.getSanitizerBoolPtr(t) 629 return sanitizerVal != nil && *sanitizerVal == false 630} 631 632// There isn't an analog of the method above (ie:isSanitizerExplicitlyEnabled) 633// because enabling a sanitizer either directly (via the blueprint) or 634// indirectly (via a mutator) sets the bool ptr to true, and you can't 635// distinguish between the cases. It isn't needed though - both cases can be 636// treated identically. 637func (sanitize *sanitize) isSanitizerEnabled(t sanitizerType) bool { 638 if sanitize == nil { 639 return false 640 } 641 642 sanitizerVal := sanitize.getSanitizerBoolPtr(t) 643 return sanitizerVal != nil && *sanitizerVal == true 644} 645 646func isSanitizableDependencyTag(tag blueprint.DependencyTag) bool { 647 t, ok := tag.(dependencyTag) 648 return ok && t.library || t == reuseObjTag 649} 650 651// Propagate sanitizer requirements down from binaries 652func sanitizerDepsMutator(t sanitizerType) func(android.TopDownMutatorContext) { 653 return func(mctx android.TopDownMutatorContext) { 654 if c, ok := mctx.Module().(*Module); ok && c.sanitize.isSanitizerEnabled(t) { 655 mctx.WalkDeps(func(child, parent android.Module) bool { 656 if !isSanitizableDependencyTag(mctx.OtherModuleDependencyTag(child)) { 657 return false 658 } 659 if d, ok := child.(*Module); ok && d.sanitize != nil && 660 !Bool(d.sanitize.Properties.Sanitize.Never) && 661 !d.sanitize.isSanitizerExplicitlyDisabled(t) { 662 if t == cfi || t == hwasan || t == scs { 663 if d.static() { 664 d.sanitize.Properties.SanitizeDep = true 665 } 666 } else { 667 d.sanitize.Properties.SanitizeDep = true 668 } 669 } 670 return true 671 }) 672 } else if sanitizeable, ok := mctx.Module().(Sanitizeable); ok { 673 // If an APEX module includes a lib which is enabled for a sanitizer T, then 674 // the APEX module is also enabled for the same sanitizer type. 675 mctx.VisitDirectDeps(func(child android.Module) { 676 if c, ok := child.(*Module); ok && c.sanitize.isSanitizerEnabled(t) { 677 sanitizeable.EnableSanitizer(t.name()) 678 } 679 }) 680 } 681 } 682} 683 684// Propagate the ubsan minimal runtime dependency when there are integer overflow sanitized static dependencies. 685func sanitizerRuntimeDepsMutator(mctx android.TopDownMutatorContext) { 686 if c, ok := mctx.Module().(*Module); ok && c.sanitize != nil { 687 mctx.WalkDeps(func(child, parent android.Module) bool { 688 if !isSanitizableDependencyTag(mctx.OtherModuleDependencyTag(child)) { 689 return false 690 } 691 if d, ok := child.(*Module); ok && d.static() && d.sanitize != nil { 692 693 if enableMinimalRuntime(d.sanitize) { 694 // If a static dependency is built with the minimal runtime, 695 // make sure we include the ubsan minimal runtime. 696 c.sanitize.Properties.MinimalRuntimeDep = true 697 } else if Bool(d.sanitize.Properties.Sanitize.Diag.Integer_overflow) || 698 len(d.sanitize.Properties.Sanitize.Diag.Misc_undefined) > 0 { 699 // If a static dependency runs with full ubsan diagnostics, 700 // make sure we include the ubsan runtime. 701 c.sanitize.Properties.UbsanRuntimeDep = true 702 } 703 } 704 return true 705 }) 706 } 707} 708 709// Add the dependency to the runtime library for each of the sanitizer variants 710func sanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) { 711 if c, ok := mctx.Module().(*Module); ok && c.sanitize != nil { 712 if !c.Enabled() { 713 return 714 } 715 var sanitizers []string 716 var diagSanitizers []string 717 718 if Bool(c.sanitize.Properties.Sanitize.All_undefined) { 719 sanitizers = append(sanitizers, "undefined") 720 } else { 721 if Bool(c.sanitize.Properties.Sanitize.Undefined) { 722 sanitizers = append(sanitizers, 723 "bool", 724 "integer-divide-by-zero", 725 "return", 726 "returns-nonnull-attribute", 727 "shift-exponent", 728 "unreachable", 729 "vla-bound", 730 // TODO(danalbert): The following checks currently have compiler performance issues. 731 //"alignment", 732 //"bounds", 733 //"enum", 734 //"float-cast-overflow", 735 //"float-divide-by-zero", 736 //"nonnull-attribute", 737 //"null", 738 //"shift-base", 739 //"signed-integer-overflow", 740 // TODO(danalbert): Fix UB in libc++'s __tree so we can turn this on. 741 // https://llvm.org/PR19302 742 // http://reviews.llvm.org/D6974 743 // "object-size", 744 ) 745 } 746 sanitizers = append(sanitizers, c.sanitize.Properties.Sanitize.Misc_undefined...) 747 } 748 749 if Bool(c.sanitize.Properties.Sanitize.Diag.Undefined) { 750 diagSanitizers = append(diagSanitizers, "undefined") 751 } 752 753 diagSanitizers = append(diagSanitizers, c.sanitize.Properties.Sanitize.Diag.Misc_undefined...) 754 755 if Bool(c.sanitize.Properties.Sanitize.Address) { 756 sanitizers = append(sanitizers, "address") 757 diagSanitizers = append(diagSanitizers, "address") 758 } 759 760 if Bool(c.sanitize.Properties.Sanitize.Hwaddress) { 761 sanitizers = append(sanitizers, "hwaddress") 762 } 763 764 if Bool(c.sanitize.Properties.Sanitize.Thread) { 765 sanitizers = append(sanitizers, "thread") 766 } 767 768 if Bool(c.sanitize.Properties.Sanitize.Safestack) { 769 sanitizers = append(sanitizers, "safe-stack") 770 } 771 772 if Bool(c.sanitize.Properties.Sanitize.Cfi) { 773 sanitizers = append(sanitizers, "cfi") 774 775 if Bool(c.sanitize.Properties.Sanitize.Diag.Cfi) { 776 diagSanitizers = append(diagSanitizers, "cfi") 777 } 778 } 779 780 if Bool(c.sanitize.Properties.Sanitize.Integer_overflow) { 781 sanitizers = append(sanitizers, "unsigned-integer-overflow") 782 sanitizers = append(sanitizers, "signed-integer-overflow") 783 if Bool(c.sanitize.Properties.Sanitize.Diag.Integer_overflow) { 784 diagSanitizers = append(diagSanitizers, "unsigned-integer-overflow") 785 diagSanitizers = append(diagSanitizers, "signed-integer-overflow") 786 } 787 } 788 789 if Bool(c.sanitize.Properties.Sanitize.Scudo) { 790 sanitizers = append(sanitizers, "scudo") 791 } 792 793 if Bool(c.sanitize.Properties.Sanitize.Scs) { 794 sanitizers = append(sanitizers, "shadow-call-stack") 795 } 796 797 // Save the list of sanitizers. These will be used again when generating 798 // the build rules (for Cflags, etc.) 799 c.sanitize.Properties.Sanitizers = sanitizers 800 c.sanitize.Properties.DiagSanitizers = diagSanitizers 801 802 // Determine the runtime library required 803 runtimeLibrary := "" 804 toolchain := c.toolchain(mctx) 805 if Bool(c.sanitize.Properties.Sanitize.Address) { 806 runtimeLibrary = config.AddressSanitizerRuntimeLibrary(toolchain) 807 } else if Bool(c.sanitize.Properties.Sanitize.Hwaddress) { 808 if c.staticBinary() { 809 runtimeLibrary = config.HWAddressSanitizerStaticLibrary(toolchain) 810 } else { 811 runtimeLibrary = config.HWAddressSanitizerRuntimeLibrary(toolchain) 812 } 813 } else if Bool(c.sanitize.Properties.Sanitize.Thread) { 814 runtimeLibrary = config.ThreadSanitizerRuntimeLibrary(toolchain) 815 } else if Bool(c.sanitize.Properties.Sanitize.Scudo) { 816 if len(diagSanitizers) == 0 && !c.sanitize.Properties.UbsanRuntimeDep { 817 runtimeLibrary = config.ScudoMinimalRuntimeLibrary(toolchain) 818 } else { 819 runtimeLibrary = config.ScudoRuntimeLibrary(toolchain) 820 } 821 } else if len(diagSanitizers) > 0 || c.sanitize.Properties.UbsanRuntimeDep { 822 runtimeLibrary = config.UndefinedBehaviorSanitizerRuntimeLibrary(toolchain) 823 } 824 825 if mctx.Device() && runtimeLibrary != "" { 826 if inList(runtimeLibrary, llndkLibraries) && !c.static() && c.useVndk() { 827 runtimeLibrary = runtimeLibrary + llndkLibrarySuffix 828 } 829 830 // Adding dependency to the runtime library. We are using *FarVariation* 831 // because the runtime libraries themselves are not mutated by sanitizer 832 // mutators and thus don't have sanitizer variants whereas this module 833 // has been already mutated. 834 // 835 // Note that by adding dependency with {static|shared}DepTag, the lib is 836 // added to libFlags and LOCAL_SHARED_LIBRARIES by cc.Module 837 if c.staticBinary() { 838 // static executable gets static runtime libs 839 mctx.AddFarVariationDependencies([]blueprint.Variation{ 840 {Mutator: "link", Variation: "static"}, 841 {Mutator: "image", Variation: c.imageVariation()}, 842 {Mutator: "arch", Variation: mctx.Target().String()}, 843 }, staticDepTag, runtimeLibrary) 844 } else if !c.static() { 845 // dynamic executable and shared libs get shared runtime libs 846 mctx.AddFarVariationDependencies([]blueprint.Variation{ 847 {Mutator: "link", Variation: "shared"}, 848 {Mutator: "image", Variation: c.imageVariation()}, 849 {Mutator: "arch", Variation: mctx.Target().String()}, 850 }, earlySharedDepTag, runtimeLibrary) 851 } 852 // static lib does not have dependency to the runtime library. The 853 // dependency will be added to the executables or shared libs using 854 // the static lib. 855 } 856 } 857} 858 859type Sanitizeable interface { 860 android.Module 861 IsSanitizerEnabled(ctx android.BaseModuleContext, sanitizerName string) bool 862 EnableSanitizer(sanitizerName string) 863} 864 865// Create sanitized variants for modules that need them 866func sanitizerMutator(t sanitizerType) func(android.BottomUpMutatorContext) { 867 return func(mctx android.BottomUpMutatorContext) { 868 if c, ok := mctx.Module().(*Module); ok && c.sanitize != nil { 869 if c.isDependencyRoot() && c.sanitize.isSanitizerEnabled(t) { 870 modules := mctx.CreateVariations(t.variationName()) 871 modules[0].(*Module).sanitize.SetSanitizer(t, true) 872 } else if c.sanitize.isSanitizerEnabled(t) || c.sanitize.Properties.SanitizeDep { 873 // Save original sanitizer status before we assign values to variant 874 // 0 as that overwrites the original. 875 isSanitizerEnabled := c.sanitize.isSanitizerEnabled(t) 876 877 modules := mctx.CreateVariations("", t.variationName()) 878 modules[0].(*Module).sanitize.SetSanitizer(t, false) 879 modules[1].(*Module).sanitize.SetSanitizer(t, true) 880 881 modules[0].(*Module).sanitize.Properties.SanitizeDep = false 882 modules[1].(*Module).sanitize.Properties.SanitizeDep = false 883 884 // We don't need both variants active for anything but CFI-enabled 885 // target static libraries, so suppress the appropriate variant in 886 // all other cases. 887 if t == cfi { 888 if c.static() { 889 if !mctx.Device() { 890 if isSanitizerEnabled { 891 modules[0].(*Module).Properties.PreventInstall = true 892 modules[0].(*Module).Properties.HideFromMake = true 893 } else { 894 modules[1].(*Module).Properties.PreventInstall = true 895 modules[1].(*Module).Properties.HideFromMake = true 896 } 897 } else { 898 cfiStaticLibs := cfiStaticLibs(mctx.Config()) 899 900 cfiStaticLibsMutex.Lock() 901 *cfiStaticLibs = append(*cfiStaticLibs, c.Name()) 902 cfiStaticLibsMutex.Unlock() 903 } 904 } else { 905 modules[0].(*Module).Properties.PreventInstall = true 906 modules[0].(*Module).Properties.HideFromMake = true 907 } 908 } else if t == asan { 909 if mctx.Device() { 910 // CFI and ASAN are currently mutually exclusive so disable 911 // CFI if this is an ASAN variant. 912 modules[1].(*Module).sanitize.Properties.InSanitizerDir = true 913 modules[1].(*Module).sanitize.SetSanitizer(cfi, false) 914 } 915 if isSanitizerEnabled { 916 modules[0].(*Module).Properties.PreventInstall = true 917 modules[0].(*Module).Properties.HideFromMake = true 918 } else { 919 modules[1].(*Module).Properties.PreventInstall = true 920 modules[1].(*Module).Properties.HideFromMake = true 921 } 922 } else if t == scs { 923 // We don't currently link any static libraries built with make into 924 // libraries built with SCS, so we don't need logic for propagating 925 // SCSness of dependencies into make. 926 if !c.static() { 927 if isSanitizerEnabled { 928 modules[0].(*Module).Properties.PreventInstall = true 929 modules[0].(*Module).Properties.HideFromMake = true 930 } else { 931 modules[1].(*Module).Properties.PreventInstall = true 932 modules[1].(*Module).Properties.HideFromMake = true 933 } 934 } 935 } else if t == hwasan { 936 if mctx.Device() { 937 // CFI and HWASAN are currently mutually exclusive so disable 938 // CFI if this is an HWASAN variant. 939 modules[1].(*Module).sanitize.SetSanitizer(cfi, false) 940 } 941 942 if c.static() { 943 if c.useVndk() { 944 hwasanVendorStaticLibs := hwasanVendorStaticLibs(mctx.Config()) 945 hwasanStaticLibsMutex.Lock() 946 *hwasanVendorStaticLibs = append(*hwasanVendorStaticLibs, c.Name()) 947 hwasanStaticLibsMutex.Unlock() 948 } else { 949 hwasanStaticLibs := hwasanStaticLibs(mctx.Config()) 950 hwasanStaticLibsMutex.Lock() 951 *hwasanStaticLibs = append(*hwasanStaticLibs, c.Name()) 952 hwasanStaticLibsMutex.Unlock() 953 } 954 } else { 955 if isSanitizerEnabled { 956 modules[0].(*Module).Properties.PreventInstall = true 957 modules[0].(*Module).Properties.HideFromMake = true 958 } else { 959 modules[1].(*Module).Properties.PreventInstall = true 960 modules[1].(*Module).Properties.HideFromMake = true 961 } 962 } 963 } 964 } 965 c.sanitize.Properties.SanitizeDep = false 966 } else if sanitizeable, ok := mctx.Module().(Sanitizeable); ok && sanitizeable.IsSanitizerEnabled(mctx, t.name()) { 967 // APEX modules fall here 968 mctx.CreateVariations(t.variationName()) 969 } 970 } 971} 972 973var cfiStaticLibsKey = android.NewOnceKey("cfiStaticLibs") 974 975func cfiStaticLibs(config android.Config) *[]string { 976 return config.Once(cfiStaticLibsKey, func() interface{} { 977 return &[]string{} 978 }).(*[]string) 979} 980 981var hwasanStaticLibsKey = android.NewOnceKey("hwasanStaticLibs") 982 983func hwasanStaticLibs(config android.Config) *[]string { 984 return config.Once(hwasanStaticLibsKey, func() interface{} { 985 return &[]string{} 986 }).(*[]string) 987} 988 989var hwasanVendorStaticLibsKey = android.NewOnceKey("hwasanVendorStaticLibs") 990 991func hwasanVendorStaticLibs(config android.Config) *[]string { 992 return config.Once(hwasanVendorStaticLibsKey, func() interface{} { 993 return &[]string{} 994 }).(*[]string) 995} 996 997func enableMinimalRuntime(sanitize *sanitize) bool { 998 if !Bool(sanitize.Properties.Sanitize.Address) && 999 !Bool(sanitize.Properties.Sanitize.Hwaddress) && 1000 (Bool(sanitize.Properties.Sanitize.Integer_overflow) || 1001 len(sanitize.Properties.Sanitize.Misc_undefined) > 0) && 1002 !(Bool(sanitize.Properties.Sanitize.Diag.Integer_overflow) || 1003 Bool(sanitize.Properties.Sanitize.Diag.Cfi) || 1004 len(sanitize.Properties.Sanitize.Diag.Misc_undefined) > 0) { 1005 return true 1006 } 1007 return false 1008} 1009 1010func cfiMakeVarsProvider(ctx android.MakeVarsContext) { 1011 cfiStaticLibs := cfiStaticLibs(ctx.Config()) 1012 sort.Strings(*cfiStaticLibs) 1013 ctx.Strict("SOONG_CFI_STATIC_LIBRARIES", strings.Join(*cfiStaticLibs, " ")) 1014} 1015 1016func hwasanMakeVarsProvider(ctx android.MakeVarsContext) { 1017 hwasanStaticLibs := hwasanStaticLibs(ctx.Config()) 1018 sort.Strings(*hwasanStaticLibs) 1019 ctx.Strict("SOONG_HWASAN_STATIC_LIBRARIES", strings.Join(*hwasanStaticLibs, " ")) 1020 1021 hwasanVendorStaticLibs := hwasanVendorStaticLibs(ctx.Config()) 1022 sort.Strings(*hwasanVendorStaticLibs) 1023 ctx.Strict("SOONG_HWASAN_VENDOR_STATIC_LIBRARIES", strings.Join(*hwasanVendorStaticLibs, " ")) 1024} 1025