• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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