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 15 package cc 16 17 import ( 18 "fmt" 19 "io" 20 "strings" 21 22 "github.com/google/blueprint" 23 24 "android/soong/android" 25 "android/soong/cc/config" 26 ) 27 28 var ( 29 // Any C flags added by sanitizer which libTooling tools may not 30 // understand also need to be added to ClangLibToolingUnknownCflags in 31 // cc/config/clang.go 32 33 asanCflags = []string{"-fno-omit-frame-pointer"} 34 asanLdflags = []string{"-Wl,-u,__asan_preinit"} 35 asanLibs = []string{"libasan"} 36 37 cfiCflags = []string{"-flto", "-fsanitize-cfi-cross-dso", "-fvisibility=default", 38 "-fsanitize-blacklist=external/compiler-rt/lib/cfi/cfi_blacklist.txt"} 39 // FIXME: revert the __cfi_check flag when clang is updated to r280031. 40 cfiLdflags = []string{"-flto", "-fsanitize-cfi-cross-dso", "-fsanitize=cfi", 41 "-Wl,-plugin-opt,O1 -Wl,-export-dynamic-symbol=__cfi_check"} 42 cfiArflags = []string{"--plugin ${config.ClangBin}/../lib64/LLVMgold.so"} 43 44 intOverflowCflags = []string{"-fsanitize-blacklist=build/soong/cc/config/integer_overflow_blacklist.txt"} 45 ) 46 47 type sanitizerType int 48 49 func boolPtr(v bool) *bool { 50 if v { 51 return &v 52 } else { 53 return nil 54 } 55 } 56 57 const ( 58 asan sanitizerType = iota + 1 59 tsan 60 intOverflow 61 ) 62 63 func (t sanitizerType) String() string { 64 switch t { 65 case asan: 66 return "asan" 67 case tsan: 68 return "tsan" 69 case intOverflow: 70 return "intOverflow" 71 default: 72 panic(fmt.Errorf("unknown sanitizerType %d", t)) 73 } 74 } 75 76 type SanitizeProperties struct { 77 // enable AddressSanitizer, ThreadSanitizer, or UndefinedBehaviorSanitizer 78 Sanitize struct { 79 Never bool `android:"arch_variant"` 80 81 // main sanitizers 82 Address *bool `android:"arch_variant"` 83 Thread *bool `android:"arch_variant"` 84 85 // local sanitizers 86 Undefined *bool `android:"arch_variant"` 87 All_undefined *bool `android:"arch_variant"` 88 Misc_undefined []string `android:"arch_variant"` 89 Coverage *bool `android:"arch_variant"` 90 Safestack *bool `android:"arch_variant"` 91 Cfi *bool `android:"arch_variant"` 92 Integer_overflow *bool `android:"arch_variant"` 93 94 // Sanitizers to run in the diagnostic mode (as opposed to the release mode). 95 // Replaces abort() on error with a human-readable error message. 96 // Address and Thread sanitizers always run in diagnostic mode. 97 Diag struct { 98 Undefined *bool `android:"arch_variant"` 99 Cfi *bool `android:"arch_variant"` 100 Integer_overflow *bool `android:"arch_variant"` 101 Misc_undefined []string `android:"arch_variant"` 102 } 103 104 // value to pass to -fsanitize-recover= 105 Recover []string 106 107 // value to pass to -fsanitize-blacklist 108 Blacklist *string 109 } `android:"arch_variant"` 110 111 SanitizerEnabled bool `blueprint:"mutated"` 112 SanitizeDep bool `blueprint:"mutated"` 113 InSanitizerDir bool `blueprint:"mutated"` 114 } 115 116 type sanitize struct { 117 Properties SanitizeProperties 118 119 runtimeLibrary string 120 androidMkRuntimeLibrary string 121 } 122 123 func (sanitize *sanitize) props() []interface{} { 124 return []interface{}{&sanitize.Properties} 125 } 126 127 func (sanitize *sanitize) begin(ctx BaseModuleContext) { 128 s := &sanitize.Properties.Sanitize 129 130 // Don't apply sanitizers to NDK code. 131 if ctx.sdk() { 132 s.Never = true 133 } 134 135 // Never always wins. 136 if s.Never { 137 return 138 } 139 140 var globalSanitizers []string 141 var globalSanitizersDiag []string 142 143 if ctx.clang() { 144 if ctx.Host() { 145 globalSanitizers = ctx.AConfig().SanitizeHost() 146 } else { 147 arches := ctx.AConfig().SanitizeDeviceArch() 148 if len(arches) == 0 || inList(ctx.Arch().ArchType.Name, arches) { 149 globalSanitizers = ctx.AConfig().SanitizeDevice() 150 globalSanitizersDiag = ctx.AConfig().SanitizeDeviceDiag() 151 } 152 } 153 } 154 155 if len(globalSanitizers) > 0 { 156 var found bool 157 if found, globalSanitizers = removeFromList("undefined", globalSanitizers); found && s.All_undefined == nil { 158 s.All_undefined = boolPtr(true) 159 } 160 161 if found, globalSanitizers = removeFromList("default-ub", globalSanitizers); found && s.Undefined == nil { 162 s.Undefined = boolPtr(true) 163 } 164 165 if found, globalSanitizers = removeFromList("address", globalSanitizers); found { 166 if s.Address == nil { 167 s.Address = boolPtr(true) 168 } else if *s.Address == false { 169 // Coverage w/o address is an error. If globalSanitizers includes both, and the module 170 // disables address, then disable coverage as well. 171 _, globalSanitizers = removeFromList("coverage", globalSanitizers) 172 } 173 } 174 175 if found, globalSanitizers = removeFromList("thread", globalSanitizers); found && s.Thread == nil { 176 s.Thread = boolPtr(true) 177 } 178 179 if found, globalSanitizers = removeFromList("coverage", globalSanitizers); found && s.Coverage == nil { 180 s.Coverage = boolPtr(true) 181 } 182 183 if found, globalSanitizers = removeFromList("safe-stack", globalSanitizers); found && s.Safestack == nil { 184 s.Safestack = boolPtr(true) 185 } 186 187 if found, globalSanitizers = removeFromList("cfi", globalSanitizers); found && s.Cfi == nil { 188 s.Cfi = boolPtr(true) 189 } 190 191 if found, globalSanitizers = removeFromList("integer_overflow", globalSanitizers); found && s.Integer_overflow == nil { 192 if !ctx.AConfig().IntegerOverflowDisabledForPath(ctx.ModuleDir()) { 193 s.Integer_overflow = boolPtr(true) 194 } 195 } 196 197 if len(globalSanitizers) > 0 { 198 ctx.ModuleErrorf("unknown global sanitizer option %s", globalSanitizers[0]) 199 } 200 201 if found, globalSanitizersDiag = removeFromList("integer_overflow", globalSanitizersDiag); found && 202 s.Diag.Integer_overflow == nil && Bool(s.Integer_overflow) { 203 s.Diag.Integer_overflow = boolPtr(true) 204 } 205 206 if len(globalSanitizersDiag) > 0 { 207 ctx.ModuleErrorf("unknown global sanitizer diagnostics option %s", globalSanitizersDiag[0]) 208 } 209 } 210 211 // CFI needs gold linker, and mips toolchain does not have one. 212 if !ctx.AConfig().EnableCFI() || ctx.Arch().ArchType == android.Mips || ctx.Arch().ArchType == android.Mips64 { 213 s.Cfi = nil 214 s.Diag.Cfi = nil 215 } 216 217 // Also disable CFI for arm32 until b/35157333 is fixed. 218 if ctx.Arch().ArchType == android.Arm { 219 s.Cfi = nil 220 s.Diag.Cfi = nil 221 } 222 223 // Also disable CFI if ASAN is enabled. 224 if Bool(s.Address) { 225 s.Cfi = nil 226 s.Diag.Cfi = nil 227 } 228 229 if ctx.staticBinary() { 230 s.Address = nil 231 s.Coverage = nil 232 s.Thread = nil 233 } 234 235 if Bool(s.All_undefined) { 236 s.Undefined = nil 237 } 238 239 if !ctx.toolchain().Is64Bit() { 240 // TSAN and SafeStack are not supported on 32-bit architectures 241 s.Thread = nil 242 s.Safestack = nil 243 // TODO(ccross): error for compile_multilib = "32"? 244 } 245 246 if ctx.Os() != android.Windows && (Bool(s.All_undefined) || Bool(s.Undefined) || Bool(s.Address) || Bool(s.Thread) || 247 Bool(s.Coverage) || Bool(s.Safestack) || Bool(s.Cfi) || Bool(s.Integer_overflow) || len(s.Misc_undefined) > 0) { 248 sanitize.Properties.SanitizerEnabled = true 249 } 250 251 if Bool(s.Coverage) { 252 if !Bool(s.Address) { 253 ctx.ModuleErrorf(`Use of "coverage" also requires "address"`) 254 } 255 } 256 } 257 258 func (sanitize *sanitize) deps(ctx BaseModuleContext, deps Deps) Deps { 259 if !sanitize.Properties.SanitizerEnabled { // || c.static() { 260 return deps 261 } 262 263 if ctx.Device() { 264 if Bool(sanitize.Properties.Sanitize.Address) { 265 deps.StaticLibs = append(deps.StaticLibs, asanLibs...) 266 } 267 } 268 269 return deps 270 } 271 272 func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags) Flags { 273 if !sanitize.Properties.SanitizerEnabled { 274 return flags 275 } 276 277 if !ctx.clang() { 278 ctx.ModuleErrorf("Use of sanitizers requires clang") 279 } 280 281 var sanitizers []string 282 var diagSanitizers []string 283 284 if Bool(sanitize.Properties.Sanitize.All_undefined) { 285 sanitizers = append(sanitizers, "undefined") 286 if ctx.Device() { 287 ctx.ModuleErrorf("ubsan is not yet supported on the device") 288 } 289 } else { 290 if Bool(sanitize.Properties.Sanitize.Undefined) { 291 sanitizers = append(sanitizers, 292 "bool", 293 "integer-divide-by-zero", 294 "return", 295 "returns-nonnull-attribute", 296 "shift-exponent", 297 "unreachable", 298 "vla-bound", 299 // TODO(danalbert): The following checks currently have compiler performance issues. 300 //"alignment", 301 //"bounds", 302 //"enum", 303 //"float-cast-overflow", 304 //"float-divide-by-zero", 305 //"nonnull-attribute", 306 //"null", 307 //"shift-base", 308 //"signed-integer-overflow", 309 // TODO(danalbert): Fix UB in libc++'s __tree so we can turn this on. 310 // https://llvm.org/PR19302 311 // http://reviews.llvm.org/D6974 312 // "object-size", 313 ) 314 } 315 sanitizers = append(sanitizers, sanitize.Properties.Sanitize.Misc_undefined...) 316 } 317 318 if Bool(sanitize.Properties.Sanitize.Diag.Undefined) { 319 diagSanitizers = append(diagSanitizers, "undefined") 320 } 321 322 diagSanitizers = append(diagSanitizers, sanitize.Properties.Sanitize.Diag.Misc_undefined...) 323 324 if Bool(sanitize.Properties.Sanitize.Address) { 325 if ctx.Arch().ArchType == android.Arm { 326 // Frame pointer based unwinder in ASan requires ARM frame setup. 327 // TODO: put in flags? 328 flags.RequiredInstructionSet = "arm" 329 } 330 flags.CFlags = append(flags.CFlags, asanCflags...) 331 flags.LdFlags = append(flags.LdFlags, asanLdflags...) 332 333 if ctx.Host() { 334 // -nodefaultlibs (provided with libc++) prevents the driver from linking 335 // libraries needed with -fsanitize=address. http://b/18650275 (WAI) 336 flags.LdFlags = append(flags.LdFlags, "-lm", "-lpthread") 337 flags.LdFlags = append(flags.LdFlags, "-Wl,--no-as-needed") 338 } else { 339 flags.CFlags = append(flags.CFlags, "-mllvm", "-asan-globals=0") 340 flags.DynamicLinker = "/system/bin/linker_asan" 341 if flags.Toolchain.Is64Bit() { 342 flags.DynamicLinker += "64" 343 } 344 } 345 sanitizers = append(sanitizers, "address") 346 diagSanitizers = append(diagSanitizers, "address") 347 } 348 349 if Bool(sanitize.Properties.Sanitize.Coverage) { 350 flags.CFlags = append(flags.CFlags, "-fsanitize-coverage=trace-pc-guard") 351 } 352 353 if Bool(sanitize.Properties.Sanitize.Safestack) { 354 sanitizers = append(sanitizers, "safe-stack") 355 } 356 357 if Bool(sanitize.Properties.Sanitize.Cfi) { 358 if ctx.Arch().ArchType == android.Arm { 359 // __cfi_check needs to be built as Thumb (see the code in linker_cfi.cpp). LLVM is not set up 360 // to do this on a function basis, so force Thumb on the entire module. 361 flags.RequiredInstructionSet = "thumb" 362 // Workaround for b/33678192. CFI jumptables need Thumb2 codegen. Revert when 363 // Clang is updated past r290384. 364 flags.LdFlags = append(flags.LdFlags, "-march=armv7-a") 365 } 366 sanitizers = append(sanitizers, "cfi") 367 flags.CFlags = append(flags.CFlags, cfiCflags...) 368 flags.LdFlags = append(flags.LdFlags, cfiLdflags...) 369 flags.ArFlags = append(flags.ArFlags, cfiArflags...) 370 if Bool(sanitize.Properties.Sanitize.Diag.Cfi) { 371 diagSanitizers = append(diagSanitizers, "cfi") 372 } 373 } 374 375 if Bool(sanitize.Properties.Sanitize.Integer_overflow) { 376 if !ctx.static() { 377 sanitizers = append(sanitizers, "unsigned-integer-overflow") 378 sanitizers = append(sanitizers, "signed-integer-overflow") 379 flags.CFlags = append(flags.CFlags, intOverflowCflags...) 380 if Bool(sanitize.Properties.Sanitize.Diag.Integer_overflow) { 381 diagSanitizers = append(diagSanitizers, "unsigned-integer-overflow") 382 diagSanitizers = append(diagSanitizers, "signed-integer-overflow") 383 } 384 } 385 } 386 387 if len(sanitizers) > 0 { 388 sanitizeArg := "-fsanitize=" + strings.Join(sanitizers, ",") 389 flags.CFlags = append(flags.CFlags, sanitizeArg) 390 if ctx.Host() { 391 flags.CFlags = append(flags.CFlags, "-fno-sanitize-recover=all") 392 flags.LdFlags = append(flags.LdFlags, sanitizeArg) 393 if ctx.Os() == android.Linux { 394 flags.LdFlags = append(flags.LdFlags, "-lrt") 395 } 396 flags.LdFlags = append(flags.LdFlags, "-ldl") 397 // Host sanitizers only link symbols in the final executable, so 398 // there will always be undefined symbols in intermediate libraries. 399 _, flags.LdFlags = removeFromList("-Wl,--no-undefined", flags.LdFlags) 400 } else { 401 flags.CFlags = append(flags.CFlags, "-fsanitize-trap=all", "-ftrap-function=abort") 402 } 403 } 404 405 if len(diagSanitizers) > 0 { 406 flags.CFlags = append(flags.CFlags, "-fno-sanitize-trap="+strings.Join(diagSanitizers, ",")) 407 } 408 // FIXME: enable RTTI if diag + (cfi or vptr) 409 410 if sanitize.Properties.Sanitize.Recover != nil { 411 flags.CFlags = append(flags.CFlags, "-fsanitize-recover="+ 412 strings.Join(sanitize.Properties.Sanitize.Recover, ",")) 413 } 414 415 // Link a runtime library if needed. 416 runtimeLibrary := "" 417 if Bool(sanitize.Properties.Sanitize.Address) { 418 runtimeLibrary = config.AddressSanitizerRuntimeLibrary(ctx.toolchain()) 419 } else if len(diagSanitizers) > 0 { 420 runtimeLibrary = config.UndefinedBehaviorSanitizerRuntimeLibrary(ctx.toolchain()) 421 } 422 423 if runtimeLibrary != "" { 424 // ASan runtime library must be the first in the link order. 425 flags.libFlags = append([]string{ 426 "${config.ClangAsanLibDir}/" + runtimeLibrary + ctx.toolchain().ShlibSuffix(), 427 }, flags.libFlags...) 428 sanitize.runtimeLibrary = runtimeLibrary 429 430 // When linking against VNDK, use the vendor variant of the runtime lib 431 sanitize.androidMkRuntimeLibrary = sanitize.runtimeLibrary 432 if ctx.vndk() { 433 sanitize.androidMkRuntimeLibrary = sanitize.runtimeLibrary + vendorSuffix 434 } 435 } 436 437 blacklist := android.OptionalPathForModuleSrc(ctx, sanitize.Properties.Sanitize.Blacklist) 438 if blacklist.Valid() { 439 flags.CFlags = append(flags.CFlags, "-fsanitize-blacklist="+blacklist.String()) 440 flags.CFlagsDeps = append(flags.CFlagsDeps, blacklist.Path()) 441 } 442 443 return flags 444 } 445 446 func (sanitize *sanitize) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { 447 ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) error { 448 if sanitize.androidMkRuntimeLibrary != "" { 449 fmt.Fprintln(w, "LOCAL_SHARED_LIBRARIES += "+sanitize.androidMkRuntimeLibrary) 450 } 451 452 return nil 453 }) 454 } 455 456 func (sanitize *sanitize) inSanitizerDir() bool { 457 return sanitize.Properties.InSanitizerDir 458 } 459 460 func (sanitize *sanitize) Sanitizer(t sanitizerType) bool { 461 if sanitize == nil { 462 return false 463 } 464 465 switch t { 466 case asan: 467 return Bool(sanitize.Properties.Sanitize.Address) 468 case tsan: 469 return Bool(sanitize.Properties.Sanitize.Thread) 470 case intOverflow: 471 return Bool(sanitize.Properties.Sanitize.Integer_overflow) 472 default: 473 panic(fmt.Errorf("unknown sanitizerType %d", t)) 474 } 475 } 476 477 func (sanitize *sanitize) SetSanitizer(t sanitizerType, b bool) { 478 switch t { 479 case asan: 480 sanitize.Properties.Sanitize.Address = boolPtr(b) 481 if !b { 482 sanitize.Properties.Sanitize.Coverage = nil 483 } 484 case tsan: 485 sanitize.Properties.Sanitize.Thread = boolPtr(b) 486 case intOverflow: 487 sanitize.Properties.Sanitize.Integer_overflow = boolPtr(b) 488 default: 489 panic(fmt.Errorf("unknown sanitizerType %d", t)) 490 } 491 if b { 492 sanitize.Properties.SanitizerEnabled = true 493 } 494 } 495 496 // Propagate asan requirements down from binaries 497 func sanitizerDepsMutator(t sanitizerType) func(android.TopDownMutatorContext) { 498 return func(mctx android.TopDownMutatorContext) { 499 if c, ok := mctx.Module().(*Module); ok && c.sanitize.Sanitizer(t) { 500 mctx.VisitDepsDepthFirst(func(module blueprint.Module) { 501 if d, ok := mctx.Module().(*Module); ok && c.sanitize != nil && 502 !c.sanitize.Properties.Sanitize.Never { 503 d.sanitize.Properties.SanitizeDep = true 504 } 505 }) 506 } 507 } 508 } 509 510 // Create asan variants for modules that need them 511 func sanitizerMutator(t sanitizerType) func(android.BottomUpMutatorContext) { 512 return func(mctx android.BottomUpMutatorContext) { 513 if c, ok := mctx.Module().(*Module); ok && c.sanitize != nil { 514 if c.isDependencyRoot() && c.sanitize.Sanitizer(t) { 515 modules := mctx.CreateVariations(t.String()) 516 modules[0].(*Module).sanitize.SetSanitizer(t, true) 517 } else if c.sanitize.Properties.SanitizeDep { 518 modules := mctx.CreateVariations("", t.String()) 519 modules[0].(*Module).sanitize.SetSanitizer(t, false) 520 modules[1].(*Module).sanitize.SetSanitizer(t, true) 521 modules[0].(*Module).sanitize.Properties.SanitizeDep = false 522 modules[1].(*Module).sanitize.Properties.SanitizeDep = false 523 if mctx.Device() { 524 modules[1].(*Module).sanitize.Properties.InSanitizerDir = true 525 } else { 526 modules[0].(*Module).Properties.PreventInstall = true 527 } 528 if mctx.AConfig().EmbeddedInMake() { 529 modules[0].(*Module).Properties.HideFromMake = true 530 } 531 } 532 c.sanitize.Properties.SanitizeDep = false 533 } 534 } 535 } 536