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{ 35 "-fno-omit-frame-pointer", 36 "-fno-experimental-new-pass-manager", 37 } 38 asanLdflags = []string{"-Wl,-u,__asan_preinit"} 39 40 hwasanCflags = []string{"-fno-omit-frame-pointer", "-Wno-frame-larger-than=", 41 "-fsanitize-hwaddress-abi=platform", 42 "-fno-experimental-new-pass-manager", 43 // The following improves debug location information 44 // availability at the cost of its accuracy. It increases 45 // the likelihood of a stack variable's frame offset 46 // to be recorded in the debug info, which is important 47 // for the quality of hwasan reports. The downside is a 48 // higher number of "optimized out" stack variables. 49 // b/112437883. 50 "-mllvm", "-instcombine-lower-dbg-declare=0", 51 // TODO(b/159343917): HWASan and GlobalISel don't play nicely, and 52 // GlobalISel is the default at -O0 on aarch64. 53 "-mllvm", "--aarch64-enable-global-isel-at-O=-1", 54 "-mllvm", "-fast-isel=false", 55 } 56 57 cfiCflags = []string{"-flto", "-fsanitize-cfi-cross-dso", 58 "-fsanitize-blacklist=external/compiler-rt/lib/cfi/cfi_blocklist.txt"} 59 // -flto and -fvisibility are required by clang when -fsanitize=cfi is 60 // used, but have no effect on assembly files 61 cfiAsflags = []string{"-flto", "-fvisibility=default"} 62 cfiLdflags = []string{"-flto", "-fsanitize-cfi-cross-dso", "-fsanitize=cfi", 63 "-Wl,-plugin-opt,O1"} 64 cfiExportsMapPath = "build/soong/cc/config/cfi_exports.map" 65 66 intOverflowCflags = []string{"-fsanitize-blacklist=build/soong/cc/config/integer_overflow_blocklist.txt"} 67 68 minimalRuntimeFlags = []string{"-fsanitize-minimal-runtime", "-fno-sanitize-trap=integer,undefined", 69 "-fno-sanitize-recover=integer,undefined"} 70 hwasanGlobalOptions = []string{"heap_history_size=1023", "stack_history_size=512", 71 "export_memory_stats=0", "max_malloc_fill_size=0"} 72) 73 74type SanitizerType int 75 76func boolPtr(v bool) *bool { 77 if v { 78 return &v 79 } else { 80 return nil 81 } 82} 83 84const ( 85 Asan SanitizerType = iota + 1 86 Hwasan 87 tsan 88 intOverflow 89 cfi 90 scs 91 Fuzzer 92 memtag_heap 93) 94 95// Name of the sanitizer variation for this sanitizer type 96func (t SanitizerType) variationName() string { 97 switch t { 98 case Asan: 99 return "asan" 100 case Hwasan: 101 return "hwasan" 102 case tsan: 103 return "tsan" 104 case intOverflow: 105 return "intOverflow" 106 case cfi: 107 return "cfi" 108 case scs: 109 return "scs" 110 case memtag_heap: 111 return "memtag_heap" 112 case Fuzzer: 113 return "fuzzer" 114 default: 115 panic(fmt.Errorf("unknown SanitizerType %d", t)) 116 } 117} 118 119// This is the sanitizer names in SANITIZE_[TARGET|HOST] 120func (t SanitizerType) name() string { 121 switch t { 122 case Asan: 123 return "address" 124 case Hwasan: 125 return "hwaddress" 126 case memtag_heap: 127 return "memtag_heap" 128 case tsan: 129 return "thread" 130 case intOverflow: 131 return "integer_overflow" 132 case cfi: 133 return "cfi" 134 case scs: 135 return "shadow-call-stack" 136 case Fuzzer: 137 return "fuzzer" 138 default: 139 panic(fmt.Errorf("unknown SanitizerType %d", t)) 140 } 141} 142 143func (*Module) SanitizerSupported(t SanitizerType) bool { 144 switch t { 145 case Asan: 146 return true 147 case Hwasan: 148 return true 149 case tsan: 150 return true 151 case intOverflow: 152 return true 153 case cfi: 154 return true 155 case scs: 156 return true 157 case Fuzzer: 158 return true 159 default: 160 return false 161 } 162} 163 164// incompatibleWithCfi returns true if a sanitizer is incompatible with CFI. 165func (t SanitizerType) incompatibleWithCfi() bool { 166 return t == Asan || t == Fuzzer || t == Hwasan 167} 168 169type SanitizeUserProps struct { 170 Never *bool `android:"arch_variant"` 171 172 // main sanitizers 173 Address *bool `android:"arch_variant"` 174 Thread *bool `android:"arch_variant"` 175 Hwaddress *bool `android:"arch_variant"` 176 177 // local sanitizers 178 Undefined *bool `android:"arch_variant"` 179 All_undefined *bool `android:"arch_variant"` 180 Misc_undefined []string `android:"arch_variant"` 181 Fuzzer *bool `android:"arch_variant"` 182 Safestack *bool `android:"arch_variant"` 183 Cfi *bool `android:"arch_variant"` 184 Integer_overflow *bool `android:"arch_variant"` 185 Scudo *bool `android:"arch_variant"` 186 Scs *bool `android:"arch_variant"` 187 Memtag_heap *bool `android:"arch_variant"` 188 189 // A modifier for ASAN and HWASAN for write only instrumentation 190 Writeonly *bool `android:"arch_variant"` 191 192 // Sanitizers to run in the diagnostic mode (as opposed to the release mode). 193 // Replaces abort() on error with a human-readable error message. 194 // Address and Thread sanitizers always run in diagnostic mode. 195 Diag struct { 196 Undefined *bool `android:"arch_variant"` 197 Cfi *bool `android:"arch_variant"` 198 Integer_overflow *bool `android:"arch_variant"` 199 Memtag_heap *bool `android:"arch_variant"` 200 Misc_undefined []string `android:"arch_variant"` 201 No_recover []string `android:"arch_variant"` 202 } `android:"arch_variant"` 203 204 // Sanitizers to run with flag configuration specified 205 Config struct { 206 // Enables CFI support flags for assembly-heavy libraries 207 Cfi_assembly_support *bool `android:"arch_variant"` 208 } `android:"arch_variant"` 209 210 // value to pass to -fsanitize-recover= 211 Recover []string 212 213 // value to pass to -fsanitize-blacklist 214 Blocklist *string 215} 216 217type SanitizeProperties struct { 218 // Enable AddressSanitizer, ThreadSanitizer, UndefinedBehaviorSanitizer, and 219 // others. Please see SanitizerUserProps in build/soong/cc/sanitize.go for 220 // details. 221 Sanitize SanitizeUserProps `android:"arch_variant"` 222 SanitizerEnabled bool `blueprint:"mutated"` 223 SanitizeDep bool `blueprint:"mutated"` 224 MinimalRuntimeDep bool `blueprint:"mutated"` 225 BuiltinsDep bool `blueprint:"mutated"` 226 UbsanRuntimeDep bool `blueprint:"mutated"` 227 InSanitizerDir bool `blueprint:"mutated"` 228 Sanitizers []string `blueprint:"mutated"` 229 DiagSanitizers []string `blueprint:"mutated"` 230} 231 232type sanitize struct { 233 Properties SanitizeProperties 234} 235 236// Mark this tag with a check to see if apex dependency check should be skipped 237func (t libraryDependencyTag) SkipApexAllowedDependenciesCheck() bool { 238 return t.skipApexAllowedDependenciesCheck 239} 240 241var _ android.SkipApexAllowedDependenciesCheck = (*libraryDependencyTag)(nil) 242 243func init() { 244 android.RegisterMakeVarsProvider(pctx, cfiMakeVarsProvider) 245 android.RegisterMakeVarsProvider(pctx, hwasanMakeVarsProvider) 246} 247 248func (sanitize *sanitize) props() []interface{} { 249 return []interface{}{&sanitize.Properties} 250} 251 252func (sanitize *sanitize) begin(ctx BaseModuleContext) { 253 s := &sanitize.Properties.Sanitize 254 255 // Don't apply sanitizers to NDK code. 256 if ctx.useSdk() { 257 s.Never = BoolPtr(true) 258 } 259 260 // Sanitizers do not work on Fuchsia yet. 261 if ctx.Fuchsia() { 262 s.Never = BoolPtr(true) 263 } 264 265 // Never always wins. 266 if Bool(s.Never) { 267 return 268 } 269 270 // cc_test targets default to SYNC MemTag unless explicitly set to ASYNC (via diag: {memtag_heap}). 271 if ctx.testBinary() && s.Memtag_heap == nil { 272 s.Memtag_heap = boolPtr(true) 273 s.Diag.Memtag_heap = boolPtr(true) 274 } 275 276 var globalSanitizers []string 277 var globalSanitizersDiag []string 278 279 if ctx.Host() { 280 if !ctx.Windows() { 281 globalSanitizers = ctx.Config().SanitizeHost() 282 } 283 } else { 284 arches := ctx.Config().SanitizeDeviceArch() 285 if len(arches) == 0 || inList(ctx.Arch().ArchType.Name, arches) { 286 globalSanitizers = ctx.Config().SanitizeDevice() 287 globalSanitizersDiag = ctx.Config().SanitizeDeviceDiag() 288 } 289 } 290 291 if len(globalSanitizers) > 0 { 292 var found bool 293 if found, globalSanitizers = removeFromList("undefined", globalSanitizers); found && s.All_undefined == nil { 294 s.All_undefined = boolPtr(true) 295 } 296 297 if found, globalSanitizers = removeFromList("default-ub", globalSanitizers); found && s.Undefined == nil { 298 s.Undefined = boolPtr(true) 299 } 300 301 if found, globalSanitizers = removeFromList("address", globalSanitizers); found && s.Address == nil { 302 s.Address = boolPtr(true) 303 } 304 305 if found, globalSanitizers = removeFromList("thread", globalSanitizers); found && s.Thread == nil { 306 s.Thread = boolPtr(true) 307 } 308 309 if found, globalSanitizers = removeFromList("fuzzer", globalSanitizers); found && s.Fuzzer == nil { 310 s.Fuzzer = boolPtr(true) 311 } 312 313 if found, globalSanitizers = removeFromList("safe-stack", globalSanitizers); found && s.Safestack == nil { 314 s.Safestack = boolPtr(true) 315 } 316 317 if found, globalSanitizers = removeFromList("cfi", globalSanitizers); found && s.Cfi == nil { 318 if !ctx.Config().CFIDisabledForPath(ctx.ModuleDir()) { 319 s.Cfi = boolPtr(true) 320 } 321 } 322 323 // Global integer_overflow builds do not support static libraries. 324 if found, globalSanitizers = removeFromList("integer_overflow", globalSanitizers); found && s.Integer_overflow == nil { 325 if !ctx.Config().IntegerOverflowDisabledForPath(ctx.ModuleDir()) && !ctx.static() { 326 s.Integer_overflow = boolPtr(true) 327 } 328 } 329 330 if found, globalSanitizers = removeFromList("scudo", globalSanitizers); found && s.Scudo == nil { 331 s.Scudo = boolPtr(true) 332 } 333 334 if found, globalSanitizers = removeFromList("hwaddress", globalSanitizers); found && s.Hwaddress == nil { 335 s.Hwaddress = boolPtr(true) 336 } 337 338 if found, globalSanitizers = removeFromList("writeonly", globalSanitizers); found && s.Writeonly == nil { 339 // Hwaddress and Address are set before, so we can check them here 340 // If they aren't explicitly set in the blueprint/SANITIZE_(HOST|TARGET), they would be nil instead of false 341 if s.Address == nil && s.Hwaddress == nil { 342 ctx.ModuleErrorf("writeonly modifier cannot be used without 'address' or 'hwaddress'") 343 } 344 s.Writeonly = boolPtr(true) 345 } 346 if found, globalSanitizers = removeFromList("memtag_heap", globalSanitizers); found && s.Memtag_heap == nil { 347 if !ctx.Config().MemtagHeapDisabledForPath(ctx.ModuleDir()) { 348 s.Memtag_heap = boolPtr(true) 349 } 350 } 351 352 if len(globalSanitizers) > 0 { 353 ctx.ModuleErrorf("unknown global sanitizer option %s", globalSanitizers[0]) 354 } 355 356 // Global integer_overflow builds do not support static library diagnostics. 357 if found, globalSanitizersDiag = removeFromList("integer_overflow", globalSanitizersDiag); found && 358 s.Diag.Integer_overflow == nil && Bool(s.Integer_overflow) && !ctx.static() { 359 s.Diag.Integer_overflow = boolPtr(true) 360 } 361 362 if found, globalSanitizersDiag = removeFromList("cfi", globalSanitizersDiag); found && 363 s.Diag.Cfi == nil && Bool(s.Cfi) { 364 s.Diag.Cfi = boolPtr(true) 365 } 366 367 if found, globalSanitizersDiag = removeFromList("memtag_heap", globalSanitizersDiag); found && 368 s.Diag.Memtag_heap == nil && Bool(s.Memtag_heap) { 369 s.Diag.Memtag_heap = boolPtr(true) 370 } 371 372 if len(globalSanitizersDiag) > 0 { 373 ctx.ModuleErrorf("unknown global sanitizer diagnostics option %s", globalSanitizersDiag[0]) 374 } 375 } 376 377 // Enable Memtag for all components in the include paths (for Aarch64 only) 378 if ctx.Arch().ArchType == android.Arm64 { 379 if ctx.Config().MemtagHeapSyncEnabledForPath(ctx.ModuleDir()) { 380 if s.Memtag_heap == nil { 381 s.Memtag_heap = boolPtr(true) 382 } 383 if s.Diag.Memtag_heap == nil { 384 s.Diag.Memtag_heap = boolPtr(true) 385 } 386 } else if ctx.Config().MemtagHeapAsyncEnabledForPath(ctx.ModuleDir()) { 387 if s.Memtag_heap == nil { 388 s.Memtag_heap = boolPtr(true) 389 } 390 } 391 } 392 393 // Enable CFI for all components in the include paths (for Aarch64 only) 394 if s.Cfi == nil && ctx.Config().CFIEnabledForPath(ctx.ModuleDir()) && ctx.Arch().ArchType == android.Arm64 { 395 s.Cfi = boolPtr(true) 396 if inList("cfi", ctx.Config().SanitizeDeviceDiag()) { 397 s.Diag.Cfi = boolPtr(true) 398 } 399 } 400 401 // Is CFI actually enabled? 402 if !ctx.Config().EnableCFI() { 403 s.Cfi = boolPtr(false) 404 s.Diag.Cfi = boolPtr(false) 405 } 406 407 // HWASan requires AArch64 hardware feature (top-byte-ignore). 408 if ctx.Arch().ArchType != android.Arm64 { 409 s.Hwaddress = nil 410 } 411 412 // SCS is only implemented on AArch64. 413 if ctx.Arch().ArchType != android.Arm64 { 414 s.Scs = nil 415 } 416 417 // memtag_heap is only implemented on AArch64. 418 if ctx.Arch().ArchType != android.Arm64 { 419 s.Memtag_heap = nil 420 } 421 422 // Also disable CFI if ASAN is enabled. 423 if Bool(s.Address) || Bool(s.Hwaddress) { 424 s.Cfi = boolPtr(false) 425 s.Diag.Cfi = boolPtr(false) 426 } 427 428 // Disable sanitizers that depend on the UBSan runtime for windows/darwin builds. 429 if !ctx.Os().Linux() { 430 s.Cfi = boolPtr(false) 431 s.Diag.Cfi = boolPtr(false) 432 s.Misc_undefined = nil 433 s.Undefined = nil 434 s.All_undefined = nil 435 s.Integer_overflow = nil 436 } 437 438 // Also disable CFI for VNDK variants of components 439 if ctx.isVndk() && ctx.useVndk() { 440 if ctx.static() { 441 // Cfi variant for static vndk should be captured as vendor snapshot, 442 // so don't strictly disable Cfi. 443 s.Cfi = nil 444 s.Diag.Cfi = nil 445 } else { 446 s.Cfi = boolPtr(false) 447 s.Diag.Cfi = boolPtr(false) 448 } 449 } 450 451 // HWASan ramdisk (which is built from recovery) goes over some bootloader limit. 452 // Keep libc instrumented so that ramdisk / vendor_ramdisk / recovery can run hwasan-instrumented code if necessary. 453 if (ctx.inRamdisk() || ctx.inVendorRamdisk() || ctx.inRecovery()) && !strings.HasPrefix(ctx.ModuleDir(), "bionic/libc") { 454 s.Hwaddress = nil 455 } 456 457 if ctx.staticBinary() { 458 s.Address = nil 459 s.Fuzzer = nil 460 s.Thread = nil 461 } 462 463 if Bool(s.All_undefined) { 464 s.Undefined = nil 465 } 466 467 if !ctx.toolchain().Is64Bit() { 468 // TSAN and SafeStack are not supported on 32-bit architectures 469 s.Thread = nil 470 s.Safestack = nil 471 // TODO(ccross): error for compile_multilib = "32"? 472 } 473 474 if ctx.Os() != android.Windows && (Bool(s.All_undefined) || Bool(s.Undefined) || Bool(s.Address) || Bool(s.Thread) || 475 Bool(s.Fuzzer) || Bool(s.Safestack) || Bool(s.Cfi) || Bool(s.Integer_overflow) || len(s.Misc_undefined) > 0 || 476 Bool(s.Scudo) || Bool(s.Hwaddress) || Bool(s.Scs) || Bool(s.Memtag_heap)) { 477 sanitize.Properties.SanitizerEnabled = true 478 } 479 480 // Disable Scudo if ASan or TSan is enabled, or if it's disabled globally. 481 if Bool(s.Address) || Bool(s.Thread) || Bool(s.Hwaddress) || ctx.Config().DisableScudo() { 482 s.Scudo = nil 483 } 484 485 if Bool(s.Hwaddress) { 486 s.Address = nil 487 s.Thread = nil 488 // Disable ubsan diagnosic as a workaround for a compiler bug. 489 // TODO(b/191808836): re-enable. 490 s.Diag.Undefined = nil 491 s.Diag.Integer_overflow = nil 492 s.Diag.Misc_undefined = nil 493 } 494 495 // TODO(b/131771163): CFI transiently depends on LTO, and thus Fuzzer is 496 // mutually incompatible. 497 if Bool(s.Fuzzer) { 498 s.Cfi = boolPtr(false) 499 } 500} 501 502func (sanitize *sanitize) deps(ctx BaseModuleContext, deps Deps) Deps { 503 if !sanitize.Properties.SanitizerEnabled { // || c.static() { 504 return deps 505 } 506 507 return deps 508} 509 510func toDisableImplicitIntegerChange(flags []string) bool { 511 // Returns true if any flag is fsanitize*integer, and there is 512 // no explicit flag about sanitize=implicit-integer-sign-change. 513 for _, f := range flags { 514 if strings.Contains(f, "sanitize=implicit-integer-sign-change") { 515 return false 516 } 517 } 518 for _, f := range flags { 519 if strings.HasPrefix(f, "-fsanitize") && strings.Contains(f, "integer") { 520 return true 521 } 522 } 523 return false 524} 525 526func toDisableUnsignedShiftBaseChange(flags []string) bool { 527 // Returns true if any flag is fsanitize*integer, and there is 528 // no explicit flag about sanitize=unsigned-shift-base. 529 for _, f := range flags { 530 if strings.Contains(f, "sanitize=unsigned-shift-base") { 531 return false 532 } 533 } 534 for _, f := range flags { 535 if strings.HasPrefix(f, "-fsanitize") && strings.Contains(f, "integer") { 536 return true 537 } 538 } 539 return false 540} 541 542func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags) Flags { 543 minimalRuntimeLib := config.UndefinedBehaviorSanitizerMinimalRuntimeLibrary(ctx.toolchain()) + ".a" 544 minimalRuntimePath := "${config.ClangAsanLibDir}/" + minimalRuntimeLib 545 builtinsRuntimeLib := config.BuiltinsRuntimeLibrary(ctx.toolchain()) + ".a" 546 builtinsRuntimePath := "${config.ClangAsanLibDir}/" + builtinsRuntimeLib 547 548 if sanitize.Properties.MinimalRuntimeDep { 549 flags.Local.LdFlags = append(flags.Local.LdFlags, 550 minimalRuntimePath, 551 "-Wl,--exclude-libs,"+minimalRuntimeLib) 552 } 553 554 if sanitize.Properties.BuiltinsDep { 555 flags.libFlags = append([]string{builtinsRuntimePath}, flags.libFlags...) 556 } 557 558 if !sanitize.Properties.SanitizerEnabled && !sanitize.Properties.UbsanRuntimeDep { 559 return flags 560 } 561 562 if Bool(sanitize.Properties.Sanitize.Address) { 563 if ctx.Arch().ArchType == android.Arm { 564 // Frame pointer based unwinder in ASan requires ARM frame setup. 565 // TODO: put in flags? 566 flags.RequiredInstructionSet = "arm" 567 } 568 flags.Local.CFlags = append(flags.Local.CFlags, asanCflags...) 569 flags.Local.LdFlags = append(flags.Local.LdFlags, asanLdflags...) 570 571 if Bool(sanitize.Properties.Sanitize.Writeonly) { 572 flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm", "-asan-instrument-reads=0") 573 } 574 575 if ctx.Host() { 576 // -nodefaultlibs (provided with libc++) prevents the driver from linking 577 // libraries needed with -fsanitize=address. http://b/18650275 (WAI) 578 flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--no-as-needed") 579 } else { 580 flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm", "-asan-globals=0") 581 if ctx.bootstrap() { 582 flags.DynamicLinker = "/system/bin/bootstrap/linker_asan" 583 } else { 584 flags.DynamicLinker = "/system/bin/linker_asan" 585 } 586 if flags.Toolchain.Is64Bit() { 587 flags.DynamicLinker += "64" 588 } 589 } 590 } 591 592 if Bool(sanitize.Properties.Sanitize.Hwaddress) { 593 flags.Local.CFlags = append(flags.Local.CFlags, hwasanCflags...) 594 if Bool(sanitize.Properties.Sanitize.Writeonly) { 595 flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm", "-hwasan-instrument-reads=0") 596 } 597 } 598 599 if Bool(sanitize.Properties.Sanitize.Fuzzer) { 600 flags.Local.CFlags = append(flags.Local.CFlags, "-fsanitize=fuzzer-no-link") 601 602 // TODO(b/131771163): LTO and Fuzzer support is mutually incompatible. 603 _, flags.Local.LdFlags = removeFromList("-flto", flags.Local.LdFlags) 604 _, flags.Local.CFlags = removeFromList("-flto", flags.Local.CFlags) 605 flags.Local.LdFlags = append(flags.Local.LdFlags, "-fno-lto") 606 flags.Local.CFlags = append(flags.Local.CFlags, "-fno-lto") 607 608 // TODO(b/142430592): Upstream linker scripts for sanitizer runtime libraries 609 // discard the sancov_lowest_stack symbol, because it's emulated TLS (and thus 610 // doesn't match the linker script due to the "__emutls_v." prefix). 611 flags.Local.LdFlags = append(flags.Local.LdFlags, "-fno-sanitize-coverage=stack-depth") 612 flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize-coverage=stack-depth") 613 614 // TODO(b/133876586): Experimental PM breaks sanitizer coverage. 615 flags.Local.CFlags = append(flags.Local.CFlags, "-fno-experimental-new-pass-manager") 616 617 // Disable fortify for fuzzing builds. Generally, we'll be building with 618 // UBSan or ASan here and the fortify checks pollute the stack traces. 619 flags.Local.CFlags = append(flags.Local.CFlags, "-U_FORTIFY_SOURCE") 620 621 // Build fuzzer-sanitized libraries with an $ORIGIN DT_RUNPATH. Android's 622 // linker uses DT_RUNPATH, not DT_RPATH. When we deploy cc_fuzz targets and 623 // their libraries to /data/fuzz/<arch>/lib, any transient shared library gets 624 // the DT_RUNPATH from the shared library above it, and not the executable, 625 // meaning that the lookup falls back to the system. Adding the $ORIGIN to the 626 // DT_RUNPATH here means that transient shared libraries can be found 627 // colocated with their parents. 628 flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN`) 629 } 630 631 if Bool(sanitize.Properties.Sanitize.Cfi) { 632 if ctx.Arch().ArchType == android.Arm { 633 // __cfi_check needs to be built as Thumb (see the code in linker_cfi.cpp). LLVM is not set up 634 // to do this on a function basis, so force Thumb on the entire module. 635 flags.RequiredInstructionSet = "thumb" 636 } 637 638 flags.Local.CFlags = append(flags.Local.CFlags, cfiCflags...) 639 flags.Local.AsFlags = append(flags.Local.AsFlags, cfiAsflags...) 640 if Bool(sanitize.Properties.Sanitize.Config.Cfi_assembly_support) { 641 flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize-cfi-canonical-jump-tables") 642 } 643 // Only append the default visibility flag if -fvisibility has not already been set 644 // to hidden. 645 if !inList("-fvisibility=hidden", flags.Local.CFlags) { 646 flags.Local.CFlags = append(flags.Local.CFlags, "-fvisibility=default") 647 } 648 flags.Local.LdFlags = append(flags.Local.LdFlags, cfiLdflags...) 649 650 if ctx.staticBinary() { 651 _, flags.Local.CFlags = removeFromList("-fsanitize-cfi-cross-dso", flags.Local.CFlags) 652 _, flags.Local.LdFlags = removeFromList("-fsanitize-cfi-cross-dso", flags.Local.LdFlags) 653 } 654 } 655 656 if Bool(sanitize.Properties.Sanitize.Integer_overflow) { 657 flags.Local.CFlags = append(flags.Local.CFlags, intOverflowCflags...) 658 } 659 660 if len(sanitize.Properties.Sanitizers) > 0 { 661 sanitizeArg := "-fsanitize=" + strings.Join(sanitize.Properties.Sanitizers, ",") 662 663 flags.Local.CFlags = append(flags.Local.CFlags, sanitizeArg) 664 flags.Local.AsFlags = append(flags.Local.AsFlags, sanitizeArg) 665 if ctx.Host() { 666 // Host sanitizers only link symbols in the final executable, so 667 // there will always be undefined symbols in intermediate libraries. 668 _, flags.Global.LdFlags = removeFromList("-Wl,--no-undefined", flags.Global.LdFlags) 669 flags.Local.LdFlags = append(flags.Local.LdFlags, sanitizeArg) 670 671 // non-Bionic toolchain prebuilts are missing UBSan's vptr and function sanitizers 672 if !ctx.toolchain().Bionic() { 673 flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize=vptr,function") 674 } 675 } 676 677 if enableMinimalRuntime(sanitize) { 678 flags.Local.CFlags = append(flags.Local.CFlags, strings.Join(minimalRuntimeFlags, " ")) 679 flags.libFlags = append([]string{minimalRuntimePath}, flags.libFlags...) 680 flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--exclude-libs,"+minimalRuntimeLib) 681 if !ctx.toolchain().Bionic() { 682 flags.libFlags = append([]string{builtinsRuntimePath}, flags.libFlags...) 683 } 684 } 685 686 if Bool(sanitize.Properties.Sanitize.Fuzzer) { 687 // When fuzzing, we wish to crash with diagnostics on any bug. 688 flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize-trap=all", "-fno-sanitize-recover=all") 689 } else if ctx.Host() { 690 flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize-recover=all") 691 } else { 692 flags.Local.CFlags = append(flags.Local.CFlags, "-fsanitize-trap=all", "-ftrap-function=abort") 693 } 694 // http://b/119329758, Android core does not boot up with this sanitizer yet. 695 if toDisableImplicitIntegerChange(flags.Local.CFlags) { 696 flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize=implicit-integer-sign-change") 697 } 698 // http://b/171275751, Android doesn't build with this sanitizer yet. 699 if toDisableUnsignedShiftBaseChange(flags.Local.CFlags) { 700 flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize=unsigned-shift-base") 701 } 702 } 703 704 if len(sanitize.Properties.DiagSanitizers) > 0 { 705 flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize-trap="+strings.Join(sanitize.Properties.DiagSanitizers, ",")) 706 } 707 // FIXME: enable RTTI if diag + (cfi or vptr) 708 709 if sanitize.Properties.Sanitize.Recover != nil { 710 flags.Local.CFlags = append(flags.Local.CFlags, "-fsanitize-recover="+ 711 strings.Join(sanitize.Properties.Sanitize.Recover, ",")) 712 } 713 714 if sanitize.Properties.Sanitize.Diag.No_recover != nil { 715 flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize-recover="+ 716 strings.Join(sanitize.Properties.Sanitize.Diag.No_recover, ",")) 717 } 718 719 blocklist := android.OptionalPathForModuleSrc(ctx, sanitize.Properties.Sanitize.Blocklist) 720 if blocklist.Valid() { 721 flags.Local.CFlags = append(flags.Local.CFlags, "-fsanitize-blacklist="+blocklist.String()) 722 flags.CFlagsDeps = append(flags.CFlagsDeps, blocklist.Path()) 723 } 724 725 return flags 726} 727 728func (sanitize *sanitize) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { 729 // Add a suffix for cfi/hwasan/scs-enabled static/header libraries to allow surfacing 730 // both the sanitized and non-sanitized variants to make without a name conflict. 731 if entries.Class == "STATIC_LIBRARIES" || entries.Class == "HEADER_LIBRARIES" { 732 if Bool(sanitize.Properties.Sanitize.Cfi) { 733 entries.SubName += ".cfi" 734 } 735 if Bool(sanitize.Properties.Sanitize.Hwaddress) { 736 entries.SubName += ".hwasan" 737 } 738 if Bool(sanitize.Properties.Sanitize.Scs) { 739 entries.SubName += ".scs" 740 } 741 } 742} 743 744func (sanitize *sanitize) inSanitizerDir() bool { 745 return sanitize.Properties.InSanitizerDir 746} 747 748// getSanitizerBoolPtr returns the SanitizerTypes associated bool pointer from SanitizeProperties. 749func (sanitize *sanitize) getSanitizerBoolPtr(t SanitizerType) *bool { 750 switch t { 751 case Asan: 752 return sanitize.Properties.Sanitize.Address 753 case Hwasan: 754 return sanitize.Properties.Sanitize.Hwaddress 755 case tsan: 756 return sanitize.Properties.Sanitize.Thread 757 case intOverflow: 758 return sanitize.Properties.Sanitize.Integer_overflow 759 case cfi: 760 return sanitize.Properties.Sanitize.Cfi 761 case scs: 762 return sanitize.Properties.Sanitize.Scs 763 case memtag_heap: 764 return sanitize.Properties.Sanitize.Memtag_heap 765 case Fuzzer: 766 return sanitize.Properties.Sanitize.Fuzzer 767 default: 768 panic(fmt.Errorf("unknown SanitizerType %d", t)) 769 } 770} 771 772// isUnsanitizedVariant returns true if no sanitizers are enabled. 773func (sanitize *sanitize) isUnsanitizedVariant() bool { 774 return !sanitize.isSanitizerEnabled(Asan) && 775 !sanitize.isSanitizerEnabled(Hwasan) && 776 !sanitize.isSanitizerEnabled(tsan) && 777 !sanitize.isSanitizerEnabled(cfi) && 778 !sanitize.isSanitizerEnabled(scs) && 779 !sanitize.isSanitizerEnabled(memtag_heap) && 780 !sanitize.isSanitizerEnabled(Fuzzer) 781} 782 783// isVariantOnProductionDevice returns true if variant is for production devices (no non-production sanitizers enabled). 784func (sanitize *sanitize) isVariantOnProductionDevice() bool { 785 return !sanitize.isSanitizerEnabled(Asan) && 786 !sanitize.isSanitizerEnabled(Hwasan) && 787 !sanitize.isSanitizerEnabled(tsan) && 788 !sanitize.isSanitizerEnabled(Fuzzer) 789} 790 791func (sanitize *sanitize) SetSanitizer(t SanitizerType, b bool) { 792 switch t { 793 case Asan: 794 sanitize.Properties.Sanitize.Address = boolPtr(b) 795 case Hwasan: 796 sanitize.Properties.Sanitize.Hwaddress = boolPtr(b) 797 case tsan: 798 sanitize.Properties.Sanitize.Thread = boolPtr(b) 799 case intOverflow: 800 sanitize.Properties.Sanitize.Integer_overflow = boolPtr(b) 801 case cfi: 802 sanitize.Properties.Sanitize.Cfi = boolPtr(b) 803 case scs: 804 sanitize.Properties.Sanitize.Scs = boolPtr(b) 805 case memtag_heap: 806 sanitize.Properties.Sanitize.Memtag_heap = boolPtr(b) 807 case Fuzzer: 808 sanitize.Properties.Sanitize.Fuzzer = boolPtr(b) 809 default: 810 panic(fmt.Errorf("unknown SanitizerType %d", t)) 811 } 812 if b { 813 sanitize.Properties.SanitizerEnabled = true 814 } 815} 816 817// Check if the sanitizer is explicitly disabled (as opposed to nil by 818// virtue of not being set). 819func (sanitize *sanitize) isSanitizerExplicitlyDisabled(t SanitizerType) bool { 820 if sanitize == nil { 821 return false 822 } 823 824 sanitizerVal := sanitize.getSanitizerBoolPtr(t) 825 return sanitizerVal != nil && *sanitizerVal == false 826} 827 828// There isn't an analog of the method above (ie:isSanitizerExplicitlyEnabled) 829// because enabling a sanitizer either directly (via the blueprint) or 830// indirectly (via a mutator) sets the bool ptr to true, and you can't 831// distinguish between the cases. It isn't needed though - both cases can be 832// treated identically. 833func (sanitize *sanitize) isSanitizerEnabled(t SanitizerType) bool { 834 if sanitize == nil { 835 return false 836 } 837 838 sanitizerVal := sanitize.getSanitizerBoolPtr(t) 839 return sanitizerVal != nil && *sanitizerVal == true 840} 841 842// IsSanitizableDependencyTag returns true if the dependency tag is sanitizable. 843func IsSanitizableDependencyTag(tag blueprint.DependencyTag) bool { 844 switch t := tag.(type) { 845 case dependencyTag: 846 return t == reuseObjTag || t == objDepTag 847 case libraryDependencyTag: 848 return true 849 default: 850 return false 851 } 852} 853 854func (m *Module) SanitizableDepTagChecker() SantizableDependencyTagChecker { 855 return IsSanitizableDependencyTag 856} 857 858// Determines if the current module is a static library going to be captured 859// as vendor snapshot. Such modules must create both cfi and non-cfi variants, 860// except for ones which explicitly disable cfi. 861func needsCfiForVendorSnapshot(mctx android.TopDownMutatorContext) bool { 862 if isVendorProprietaryModule(mctx) { 863 return false 864 } 865 866 c := mctx.Module().(PlatformSanitizeable) 867 868 if !c.InVendor() { 869 return false 870 } 871 872 if !c.StaticallyLinked() { 873 return false 874 } 875 876 if c.IsPrebuilt() { 877 return false 878 } 879 880 if !c.SanitizerSupported(cfi) { 881 return false 882 } 883 884 return c.SanitizePropDefined() && 885 !c.SanitizeNever() && 886 !c.IsSanitizerExplicitlyDisabled(cfi) 887} 888 889// Propagate sanitizer requirements down from binaries 890func sanitizerDepsMutator(t SanitizerType) func(android.TopDownMutatorContext) { 891 return func(mctx android.TopDownMutatorContext) { 892 if c, ok := mctx.Module().(PlatformSanitizeable); ok { 893 enabled := c.IsSanitizerEnabled(t) 894 if t == cfi && needsCfiForVendorSnapshot(mctx) { 895 // We shouldn't change the result of isSanitizerEnabled(cfi) to correctly 896 // determine defaultVariation in sanitizerMutator below. 897 // Instead, just mark SanitizeDep to forcefully create cfi variant. 898 enabled = true 899 c.SetSanitizeDep(true) 900 } 901 if enabled { 902 isSanitizableDependencyTag := c.SanitizableDepTagChecker() 903 mctx.WalkDeps(func(child, parent android.Module) bool { 904 if !isSanitizableDependencyTag(mctx.OtherModuleDependencyTag(child)) { 905 return false 906 } 907 if d, ok := child.(PlatformSanitizeable); ok && d.SanitizePropDefined() && 908 !d.SanitizeNever() && 909 !d.IsSanitizerExplicitlyDisabled(t) { 910 if t == cfi || t == Hwasan || t == scs || t == Asan { 911 if d.StaticallyLinked() && d.SanitizerSupported(t) { 912 // Rust does not support some of these sanitizers, so we need to check if it's 913 // supported before setting this true. 914 d.SetSanitizeDep(true) 915 } 916 } else { 917 d.SetSanitizeDep(true) 918 } 919 } 920 return true 921 }) 922 } 923 } else if sanitizeable, ok := mctx.Module().(Sanitizeable); ok { 924 // If an APEX module includes a lib which is enabled for a sanitizer T, then 925 // the APEX module is also enabled for the same sanitizer type. 926 mctx.VisitDirectDeps(func(child android.Module) { 927 if c, ok := child.(*Module); ok && c.sanitize.isSanitizerEnabled(t) { 928 sanitizeable.EnableSanitizer(t.name()) 929 } 930 }) 931 } 932 } 933} 934 935func (c *Module) SanitizeNever() bool { 936 return Bool(c.sanitize.Properties.Sanitize.Never) 937} 938 939func (c *Module) IsSanitizerExplicitlyDisabled(t SanitizerType) bool { 940 return c.sanitize.isSanitizerExplicitlyDisabled(t) 941} 942 943// Propagate the ubsan minimal runtime dependency when there are integer overflow sanitized static dependencies. 944func sanitizerRuntimeDepsMutator(mctx android.TopDownMutatorContext) { 945 // Change this to PlatformSanitizable when/if non-cc modules support ubsan sanitizers. 946 if c, ok := mctx.Module().(*Module); ok && c.sanitize != nil { 947 isSanitizableDependencyTag := c.SanitizableDepTagChecker() 948 mctx.WalkDeps(func(child, parent android.Module) bool { 949 if !isSanitizableDependencyTag(mctx.OtherModuleDependencyTag(child)) { 950 return false 951 } 952 953 d, ok := child.(*Module) 954 if !ok || !d.static() { 955 return false 956 } 957 if d.sanitize != nil { 958 if enableMinimalRuntime(d.sanitize) { 959 // If a static dependency is built with the minimal runtime, 960 // make sure we include the ubsan minimal runtime. 961 c.sanitize.Properties.MinimalRuntimeDep = true 962 } else if enableUbsanRuntime(d.sanitize) { 963 // If a static dependency runs with full ubsan diagnostics, 964 // make sure we include the ubsan runtime. 965 c.sanitize.Properties.UbsanRuntimeDep = true 966 } 967 968 if c.sanitize.Properties.MinimalRuntimeDep && 969 c.sanitize.Properties.UbsanRuntimeDep { 970 // both flags that this mutator might set are true, so don't bother recursing 971 return false 972 } 973 974 if c.Os() == android.Linux { 975 c.sanitize.Properties.BuiltinsDep = true 976 } 977 978 return true 979 } 980 981 if p, ok := d.linker.(*snapshotLibraryDecorator); ok { 982 if Bool(p.properties.Sanitize_minimal_dep) { 983 c.sanitize.Properties.MinimalRuntimeDep = true 984 } 985 if Bool(p.properties.Sanitize_ubsan_dep) { 986 c.sanitize.Properties.UbsanRuntimeDep = true 987 } 988 } 989 990 return false 991 }) 992 } 993} 994 995// Add the dependency to the runtime library for each of the sanitizer variants 996func sanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) { 997 if c, ok := mctx.Module().(*Module); ok && c.sanitize != nil { 998 if !c.Enabled() { 999 return 1000 } 1001 var sanitizers []string 1002 var diagSanitizers []string 1003 1004 if Bool(c.sanitize.Properties.Sanitize.All_undefined) { 1005 sanitizers = append(sanitizers, "undefined") 1006 } else { 1007 if Bool(c.sanitize.Properties.Sanitize.Undefined) { 1008 sanitizers = append(sanitizers, 1009 "bool", 1010 "integer-divide-by-zero", 1011 "return", 1012 "returns-nonnull-attribute", 1013 "shift-exponent", 1014 "unreachable", 1015 "vla-bound", 1016 // TODO(danalbert): The following checks currently have compiler performance issues. 1017 //"alignment", 1018 //"bounds", 1019 //"enum", 1020 //"float-cast-overflow", 1021 //"float-divide-by-zero", 1022 //"nonnull-attribute", 1023 //"null", 1024 //"shift-base", 1025 //"signed-integer-overflow", 1026 // TODO(danalbert): Fix UB in libc++'s __tree so we can turn this on. 1027 // https://llvm.org/PR19302 1028 // http://reviews.llvm.org/D6974 1029 // "object-size", 1030 ) 1031 } 1032 sanitizers = append(sanitizers, c.sanitize.Properties.Sanitize.Misc_undefined...) 1033 } 1034 1035 if Bool(c.sanitize.Properties.Sanitize.Diag.Undefined) { 1036 diagSanitizers = append(diagSanitizers, "undefined") 1037 } 1038 1039 diagSanitizers = append(diagSanitizers, c.sanitize.Properties.Sanitize.Diag.Misc_undefined...) 1040 1041 if Bool(c.sanitize.Properties.Sanitize.Address) { 1042 sanitizers = append(sanitizers, "address") 1043 diagSanitizers = append(diagSanitizers, "address") 1044 } 1045 1046 if Bool(c.sanitize.Properties.Sanitize.Hwaddress) { 1047 sanitizers = append(sanitizers, "hwaddress") 1048 } 1049 1050 if Bool(c.sanitize.Properties.Sanitize.Thread) { 1051 sanitizers = append(sanitizers, "thread") 1052 } 1053 1054 if Bool(c.sanitize.Properties.Sanitize.Safestack) { 1055 sanitizers = append(sanitizers, "safe-stack") 1056 } 1057 1058 if Bool(c.sanitize.Properties.Sanitize.Cfi) { 1059 sanitizers = append(sanitizers, "cfi") 1060 1061 if Bool(c.sanitize.Properties.Sanitize.Diag.Cfi) { 1062 diagSanitizers = append(diagSanitizers, "cfi") 1063 } 1064 } 1065 1066 if Bool(c.sanitize.Properties.Sanitize.Integer_overflow) { 1067 sanitizers = append(sanitizers, "unsigned-integer-overflow") 1068 sanitizers = append(sanitizers, "signed-integer-overflow") 1069 if Bool(c.sanitize.Properties.Sanitize.Diag.Integer_overflow) { 1070 diagSanitizers = append(diagSanitizers, "unsigned-integer-overflow") 1071 diagSanitizers = append(diagSanitizers, "signed-integer-overflow") 1072 } 1073 } 1074 1075 if Bool(c.sanitize.Properties.Sanitize.Scudo) { 1076 sanitizers = append(sanitizers, "scudo") 1077 } 1078 1079 if Bool(c.sanitize.Properties.Sanitize.Scs) { 1080 sanitizers = append(sanitizers, "shadow-call-stack") 1081 } 1082 1083 if Bool(c.sanitize.Properties.Sanitize.Memtag_heap) && c.Binary() { 1084 noteDep := "note_memtag_heap_async" 1085 if Bool(c.sanitize.Properties.Sanitize.Diag.Memtag_heap) { 1086 noteDep = "note_memtag_heap_sync" 1087 } 1088 // If we're using snapshots, redirect to snapshot whenever possible 1089 // TODO(b/178470649): clean manual snapshot redirections 1090 snapshot := mctx.Provider(SnapshotInfoProvider).(SnapshotInfo) 1091 if lib, ok := snapshot.StaticLibs[noteDep]; ok { 1092 noteDep = lib 1093 } 1094 depTag := libraryDependencyTag{Kind: staticLibraryDependency, wholeStatic: true} 1095 variations := append(mctx.Target().Variations(), 1096 blueprint.Variation{Mutator: "link", Variation: "static"}) 1097 if c.Device() { 1098 variations = append(variations, c.ImageVariation()) 1099 } 1100 mctx.AddFarVariationDependencies(variations, depTag, noteDep) 1101 } 1102 1103 if Bool(c.sanitize.Properties.Sanitize.Fuzzer) { 1104 sanitizers = append(sanitizers, "fuzzer-no-link") 1105 } 1106 1107 // Save the list of sanitizers. These will be used again when generating 1108 // the build rules (for Cflags, etc.) 1109 c.sanitize.Properties.Sanitizers = sanitizers 1110 c.sanitize.Properties.DiagSanitizers = diagSanitizers 1111 1112 // TODO(b/150822854) Hosts have a different default behavior and assume the runtime library is used. 1113 if c.Host() { 1114 diagSanitizers = sanitizers 1115 } 1116 1117 // Determine the runtime library required 1118 runtimeLibrary := "" 1119 var extraStaticDeps []string 1120 toolchain := c.toolchain(mctx) 1121 if Bool(c.sanitize.Properties.Sanitize.Address) { 1122 runtimeLibrary = config.AddressSanitizerRuntimeLibrary(toolchain) 1123 } else if Bool(c.sanitize.Properties.Sanitize.Hwaddress) { 1124 if c.staticBinary() { 1125 runtimeLibrary = config.HWAddressSanitizerStaticLibrary(toolchain) 1126 extraStaticDeps = []string{"libdl"} 1127 } else { 1128 runtimeLibrary = config.HWAddressSanitizerRuntimeLibrary(toolchain) 1129 } 1130 } else if Bool(c.sanitize.Properties.Sanitize.Thread) { 1131 runtimeLibrary = config.ThreadSanitizerRuntimeLibrary(toolchain) 1132 } else if Bool(c.sanitize.Properties.Sanitize.Scudo) { 1133 if len(diagSanitizers) == 0 && !c.sanitize.Properties.UbsanRuntimeDep { 1134 runtimeLibrary = config.ScudoMinimalRuntimeLibrary(toolchain) 1135 } else { 1136 runtimeLibrary = config.ScudoRuntimeLibrary(toolchain) 1137 } 1138 } else if len(diagSanitizers) > 0 || c.sanitize.Properties.UbsanRuntimeDep || 1139 Bool(c.sanitize.Properties.Sanitize.Fuzzer) || 1140 Bool(c.sanitize.Properties.Sanitize.Undefined) || 1141 Bool(c.sanitize.Properties.Sanitize.All_undefined) { 1142 runtimeLibrary = config.UndefinedBehaviorSanitizerRuntimeLibrary(toolchain) 1143 if c.staticBinary() { 1144 runtimeLibrary += ".static" 1145 } 1146 } 1147 1148 if runtimeLibrary != "" && (toolchain.Bionic() || c.sanitize.Properties.UbsanRuntimeDep) { 1149 // UBSan is supported on non-bionic linux host builds as well 1150 1151 // Adding dependency to the runtime library. We are using *FarVariation* 1152 // because the runtime libraries themselves are not mutated by sanitizer 1153 // mutators and thus don't have sanitizer variants whereas this module 1154 // has been already mutated. 1155 // 1156 // Note that by adding dependency with {static|shared}DepTag, the lib is 1157 // added to libFlags and LOCAL_SHARED_LIBRARIES by cc.Module 1158 if c.staticBinary() { 1159 deps := append(extraStaticDeps, runtimeLibrary) 1160 // If we're using snapshots, redirect to snapshot whenever possible 1161 snapshot := mctx.Provider(SnapshotInfoProvider).(SnapshotInfo) 1162 for idx, dep := range deps { 1163 if lib, ok := snapshot.StaticLibs[dep]; ok { 1164 deps[idx] = lib 1165 } 1166 } 1167 1168 // static executable gets static runtime libs 1169 depTag := libraryDependencyTag{Kind: staticLibraryDependency} 1170 variations := append(mctx.Target().Variations(), 1171 blueprint.Variation{Mutator: "link", Variation: "static"}) 1172 if c.Device() { 1173 variations = append(variations, c.ImageVariation()) 1174 } 1175 mctx.AddFarVariationDependencies(variations, depTag, deps...) 1176 } else if !c.static() && !c.Header() { 1177 // If we're using snapshots, redirect to snapshot whenever possible 1178 snapshot := mctx.Provider(SnapshotInfoProvider).(SnapshotInfo) 1179 if lib, ok := snapshot.SharedLibs[runtimeLibrary]; ok { 1180 runtimeLibrary = lib 1181 } 1182 1183 // Skip apex dependency check for sharedLibraryDependency 1184 // when sanitizer diags are enabled. Skipping the check will allow 1185 // building with diag libraries without having to list the 1186 // dependency in Apex's allowed_deps file. 1187 diagEnabled := len(diagSanitizers) > 0 1188 // dynamic executable and shared libs get shared runtime libs 1189 depTag := libraryDependencyTag{ 1190 Kind: sharedLibraryDependency, 1191 Order: earlyLibraryDependency, 1192 1193 skipApexAllowedDependenciesCheck: diagEnabled, 1194 } 1195 variations := append(mctx.Target().Variations(), 1196 blueprint.Variation{Mutator: "link", Variation: "shared"}) 1197 if c.Device() { 1198 variations = append(variations, c.ImageVariation()) 1199 } 1200 c.addSharedLibDependenciesWithVersions(mctx, variations, depTag, runtimeLibrary, "", true) 1201 } 1202 // static lib does not have dependency to the runtime library. The 1203 // dependency will be added to the executables or shared libs using 1204 // the static lib. 1205 } 1206 } 1207} 1208 1209type Sanitizeable interface { 1210 android.Module 1211 IsSanitizerEnabled(ctx android.BaseModuleContext, sanitizerName string) bool 1212 EnableSanitizer(sanitizerName string) 1213 AddSanitizerDependencies(ctx android.BottomUpMutatorContext, sanitizerName string) 1214} 1215 1216func (c *Module) MinimalRuntimeDep() bool { 1217 return c.sanitize.Properties.MinimalRuntimeDep 1218} 1219 1220func (c *Module) UbsanRuntimeDep() bool { 1221 return c.sanitize.Properties.UbsanRuntimeDep 1222} 1223 1224func (c *Module) SanitizePropDefined() bool { 1225 return c.sanitize != nil 1226} 1227 1228func (c *Module) IsSanitizerEnabled(t SanitizerType) bool { 1229 return c.sanitize.isSanitizerEnabled(t) 1230} 1231 1232func (c *Module) SanitizeDep() bool { 1233 return c.sanitize.Properties.SanitizeDep 1234} 1235 1236func (c *Module) StaticallyLinked() bool { 1237 return c.static() 1238} 1239 1240func (c *Module) SetInSanitizerDir() { 1241 if c.sanitize != nil { 1242 c.sanitize.Properties.InSanitizerDir = true 1243 } 1244} 1245 1246func (c *Module) SetSanitizer(t SanitizerType, b bool) { 1247 if c.sanitize != nil { 1248 c.sanitize.SetSanitizer(t, b) 1249 } 1250} 1251 1252func (c *Module) SetSanitizeDep(b bool) { 1253 if c.sanitize != nil { 1254 c.sanitize.Properties.SanitizeDep = b 1255 } 1256} 1257 1258var _ PlatformSanitizeable = (*Module)(nil) 1259 1260// Create sanitized variants for modules that need them 1261func sanitizerMutator(t SanitizerType) func(android.BottomUpMutatorContext) { 1262 return func(mctx android.BottomUpMutatorContext) { 1263 if c, ok := mctx.Module().(PlatformSanitizeable); ok && c.SanitizePropDefined() { 1264 if c.IsDependencyRoot() && c.IsSanitizerEnabled(t) { 1265 modules := mctx.CreateVariations(t.variationName()) 1266 modules[0].(PlatformSanitizeable).SetSanitizer(t, true) 1267 } else if c.IsSanitizerEnabled(t) || c.SanitizeDep() { 1268 isSanitizerEnabled := c.IsSanitizerEnabled(t) 1269 if c.StaticallyLinked() || c.Header() || t == Fuzzer { 1270 // Static and header libs are split into non-sanitized and sanitized variants. 1271 // Shared libs are not split. However, for asan and fuzzer, we split even for shared 1272 // libs because a library sanitized for asan/fuzzer can't be linked from a library 1273 // that isn't sanitized for asan/fuzzer. 1274 // 1275 // Note for defaultVariation: since we don't split for shared libs but for static/header 1276 // libs, it is possible for the sanitized variant of a static/header lib to depend 1277 // on non-sanitized variant of a shared lib. Such unfulfilled variation causes an 1278 // error when the module is split. defaultVariation is the name of the variation that 1279 // will be used when such a dangling dependency occurs during the split of the current 1280 // module. By setting it to the name of the sanitized variation, the dangling dependency 1281 // is redirected to the sanitized variant of the dependent module. 1282 defaultVariation := t.variationName() 1283 // Not all PlatformSanitizeable modules support the CFI sanitizer 1284 cfiSupported := mctx.Module().(PlatformSanitizeable).SanitizerSupported(cfi) 1285 mctx.SetDefaultDependencyVariation(&defaultVariation) 1286 1287 modules := mctx.CreateVariations("", t.variationName()) 1288 modules[0].(PlatformSanitizeable).SetSanitizer(t, false) 1289 modules[1].(PlatformSanitizeable).SetSanitizer(t, true) 1290 modules[0].(PlatformSanitizeable).SetSanitizeDep(false) 1291 modules[1].(PlatformSanitizeable).SetSanitizeDep(false) 1292 1293 if mctx.Device() && t.incompatibleWithCfi() && cfiSupported { 1294 // TODO: Make sure that cfi mutator runs "after" any of the sanitizers that 1295 // are incompatible with cfi 1296 modules[1].(PlatformSanitizeable).SetSanitizer(cfi, false) 1297 } 1298 1299 // For cfi/scs/hwasan, we can export both sanitized and un-sanitized variants 1300 // to Make, because the sanitized version has a different suffix in name. 1301 // For other types of sanitizers, suppress the variation that is disabled. 1302 if t != cfi && t != scs && t != Hwasan { 1303 if isSanitizerEnabled { 1304 modules[0].(PlatformSanitizeable).SetPreventInstall() 1305 modules[0].(PlatformSanitizeable).SetHideFromMake() 1306 } else { 1307 modules[1].(PlatformSanitizeable).SetPreventInstall() 1308 modules[1].(PlatformSanitizeable).SetHideFromMake() 1309 } 1310 } 1311 1312 // Export the static lib name to make 1313 if c.StaticallyLinked() && c.ExportedToMake() { 1314 if t == cfi { 1315 cfiStaticLibs(mctx.Config()).add(c, c.Module().Name()) 1316 } else if t == Hwasan { 1317 hwasanStaticLibs(mctx.Config()).add(c, c.Module().Name()) 1318 } 1319 } 1320 } else { 1321 // Shared libs are not split. Only the sanitized variant is created. 1322 modules := mctx.CreateVariations(t.variationName()) 1323 modules[0].(PlatformSanitizeable).SetSanitizer(t, true) 1324 modules[0].(PlatformSanitizeable).SetSanitizeDep(false) 1325 1326 // locate the asan libraries under /data/asan 1327 if mctx.Device() && t == Asan && isSanitizerEnabled { 1328 modules[0].(PlatformSanitizeable).SetInSanitizerDir() 1329 } 1330 1331 if mctx.Device() && t.incompatibleWithCfi() { 1332 // TODO: Make sure that cfi mutator runs "after" any of the sanitizers that 1333 // are incompatible with cfi 1334 modules[0].(PlatformSanitizeable).SetSanitizer(cfi, false) 1335 } 1336 } 1337 } 1338 c.SetSanitizeDep(false) 1339 } else if sanitizeable, ok := mctx.Module().(Sanitizeable); ok && sanitizeable.IsSanitizerEnabled(mctx, t.name()) { 1340 // APEX modules fall here 1341 sanitizeable.AddSanitizerDependencies(mctx, t.name()) 1342 mctx.CreateVariations(t.variationName()) 1343 } else if c, ok := mctx.Module().(*Module); ok { 1344 //TODO: When Rust modules have vendor support, enable this path for PlatformSanitizeable 1345 1346 // Check if it's a snapshot module supporting sanitizer 1347 if s, ok := c.linker.(snapshotSanitizer); ok && s.isSanitizerEnabled(t) { 1348 // Set default variation as above. 1349 defaultVariation := t.variationName() 1350 mctx.SetDefaultDependencyVariation(&defaultVariation) 1351 modules := mctx.CreateVariations("", t.variationName()) 1352 modules[0].(*Module).linker.(snapshotSanitizer).setSanitizerVariation(t, false) 1353 modules[1].(*Module).linker.(snapshotSanitizer).setSanitizerVariation(t, true) 1354 1355 // Export the static lib name to make 1356 if c.static() && c.ExportedToMake() { 1357 if t == cfi { 1358 // use BaseModuleName which is the name for Make. 1359 cfiStaticLibs(mctx.Config()).add(c, c.BaseModuleName()) 1360 } 1361 } 1362 } 1363 } 1364 } 1365} 1366 1367type sanitizerStaticLibsMap struct { 1368 // libsMap contains one list of modules per each image and each arch. 1369 // e.g. libs[vendor]["arm"] contains arm modules installed to vendor 1370 libsMap map[ImageVariantType]map[string][]string 1371 libsMapLock sync.Mutex 1372 sanitizerType SanitizerType 1373} 1374 1375func newSanitizerStaticLibsMap(t SanitizerType) *sanitizerStaticLibsMap { 1376 return &sanitizerStaticLibsMap{ 1377 sanitizerType: t, 1378 libsMap: make(map[ImageVariantType]map[string][]string), 1379 } 1380} 1381 1382// Add the current module to sanitizer static libs maps 1383// Each module should pass its exported name as names of Make and Soong can differ. 1384func (s *sanitizerStaticLibsMap) add(c LinkableInterface, name string) { 1385 image := GetImageVariantType(c) 1386 arch := c.Module().Target().Arch.ArchType.String() 1387 1388 s.libsMapLock.Lock() 1389 defer s.libsMapLock.Unlock() 1390 1391 if _, ok := s.libsMap[image]; !ok { 1392 s.libsMap[image] = make(map[string][]string) 1393 } 1394 1395 s.libsMap[image][arch] = append(s.libsMap[image][arch], name) 1396} 1397 1398// Exports makefile variables in the following format: 1399// SOONG_{sanitizer}_{image}_{arch}_STATIC_LIBRARIES 1400// e.g. SOONG_cfi_core_x86_STATIC_LIBRARIES 1401// These are to be used by use_soong_sanitized_static_libraries. 1402// See build/make/core/binary.mk for more details. 1403func (s *sanitizerStaticLibsMap) exportToMake(ctx android.MakeVarsContext) { 1404 for _, image := range android.SortedStringKeys(s.libsMap) { 1405 archMap := s.libsMap[ImageVariantType(image)] 1406 for _, arch := range android.SortedStringKeys(archMap) { 1407 libs := archMap[arch] 1408 sort.Strings(libs) 1409 1410 key := fmt.Sprintf( 1411 "SOONG_%s_%s_%s_STATIC_LIBRARIES", 1412 s.sanitizerType.variationName(), 1413 image, // already upper 1414 arch) 1415 1416 ctx.Strict(key, strings.Join(libs, " ")) 1417 } 1418 } 1419} 1420 1421var cfiStaticLibsKey = android.NewOnceKey("cfiStaticLibs") 1422 1423func cfiStaticLibs(config android.Config) *sanitizerStaticLibsMap { 1424 return config.Once(cfiStaticLibsKey, func() interface{} { 1425 return newSanitizerStaticLibsMap(cfi) 1426 }).(*sanitizerStaticLibsMap) 1427} 1428 1429var hwasanStaticLibsKey = android.NewOnceKey("hwasanStaticLibs") 1430 1431func hwasanStaticLibs(config android.Config) *sanitizerStaticLibsMap { 1432 return config.Once(hwasanStaticLibsKey, func() interface{} { 1433 return newSanitizerStaticLibsMap(Hwasan) 1434 }).(*sanitizerStaticLibsMap) 1435} 1436 1437func enableMinimalRuntime(sanitize *sanitize) bool { 1438 if !Bool(sanitize.Properties.Sanitize.Address) && 1439 !Bool(sanitize.Properties.Sanitize.Hwaddress) && 1440 !Bool(sanitize.Properties.Sanitize.Fuzzer) && 1441 1442 (Bool(sanitize.Properties.Sanitize.Integer_overflow) || 1443 len(sanitize.Properties.Sanitize.Misc_undefined) > 0 || 1444 Bool(sanitize.Properties.Sanitize.Undefined) || 1445 Bool(sanitize.Properties.Sanitize.All_undefined)) && 1446 1447 !(Bool(sanitize.Properties.Sanitize.Diag.Integer_overflow) || 1448 Bool(sanitize.Properties.Sanitize.Diag.Cfi) || 1449 Bool(sanitize.Properties.Sanitize.Diag.Undefined) || 1450 len(sanitize.Properties.Sanitize.Diag.Misc_undefined) > 0) { 1451 1452 return true 1453 } 1454 return false 1455} 1456 1457func (m *Module) UbsanRuntimeNeeded() bool { 1458 return enableUbsanRuntime(m.sanitize) 1459} 1460 1461func (m *Module) MinimalRuntimeNeeded() bool { 1462 return enableMinimalRuntime(m.sanitize) 1463} 1464 1465func enableUbsanRuntime(sanitize *sanitize) bool { 1466 return Bool(sanitize.Properties.Sanitize.Diag.Integer_overflow) || 1467 Bool(sanitize.Properties.Sanitize.Diag.Undefined) || 1468 len(sanitize.Properties.Sanitize.Diag.Misc_undefined) > 0 1469} 1470 1471func cfiMakeVarsProvider(ctx android.MakeVarsContext) { 1472 cfiStaticLibs(ctx.Config()).exportToMake(ctx) 1473} 1474 1475func hwasanMakeVarsProvider(ctx android.MakeVarsContext) { 1476 hwasanStaticLibs(ctx.Config()).exportToMake(ctx) 1477} 1478