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	"github.com/google/blueprint/proptools"
25
26	"android/soong/android"
27	"android/soong/cc/config"
28	"android/soong/etc"
29)
30
31var (
32	// Any C flags added by sanitizer which libTooling tools may not
33	// understand also need to be added to ClangLibToolingUnknownCflags in
34	// cc/config/clang.go
35
36	asanCflags = []string{
37		"-fno-omit-frame-pointer",
38	}
39	asanLdflags = []string{"-Wl,-u,__asan_preinit"}
40
41	// DO NOT ADD MLLVM FLAGS HERE! ADD THEM BELOW TO hwasanCommonFlags.
42	hwasanCflags = []string{
43		"-fno-omit-frame-pointer",
44		"-Wno-frame-larger-than=",
45		"-fsanitize-hwaddress-abi=platform",
46	}
47
48	// ThinLTO performs codegen during link time, thus these flags need to
49	// passed to both CFLAGS and LDFLAGS.
50	hwasanCommonflags = []string{
51		// The following improves debug location information
52		// availability at the cost of its accuracy. It increases
53		// the likelihood of a stack variable's frame offset
54		// to be recorded in the debug info, which is important
55		// for the quality of hwasan reports. The downside is a
56		// higher number of "optimized out" stack variables.
57		// b/112437883.
58		"-instcombine-lower-dbg-declare=0",
59		"-dom-tree-reachability-max-bbs-to-explore=128",
60	}
61
62	sanitizeIgnorelistPrefix = "-fsanitize-ignorelist="
63
64	cfiBlocklistPath     = "external/compiler-rt/lib/cfi"
65	cfiBlocklistFilename = "cfi_blocklist.txt"
66	cfiEnableFlag        = "-fsanitize=cfi"
67	cfiCrossDsoFlag      = "-fsanitize-cfi-cross-dso"
68	cfiCflags            = []string{"-flto", cfiCrossDsoFlag,
69		sanitizeIgnorelistPrefix + cfiBlocklistPath + "/" + cfiBlocklistFilename}
70	// -flto and -fvisibility are required by clang when -fsanitize=cfi is
71	// used, but have no effect on assembly files
72	cfiAsflags = []string{"-flto", "-fvisibility=default"}
73	cfiLdflags = []string{"-flto", cfiCrossDsoFlag, cfiEnableFlag,
74		"-Wl,-plugin-opt,O1"}
75	cfiExportsMapPath      = "build/soong/cc/config"
76	cfiExportsMapFilename  = "cfi_exports.map"
77	cfiAssemblySupportFlag = "-fno-sanitize-cfi-canonical-jump-tables"
78
79	intOverflowCflags = []string{"-fsanitize-ignorelist=build/soong/cc/config/integer_overflow_blocklist.txt"}
80
81	minimalRuntimeFlags = []string{"-fsanitize-minimal-runtime", "-fno-sanitize-trap=integer,undefined",
82		"-fno-sanitize-recover=integer,undefined"}
83	hwasanGlobalOptions = []string{"heap_history_size=1023", "stack_history_size=512",
84		"export_memory_stats=0", "max_malloc_fill_size=131072", "malloc_fill_byte=0"}
85	memtagStackCommonFlags = []string{"-march=armv8-a+memtag"}
86	memtagStackLlvmFlags   = []string{"-dom-tree-reachability-max-bbs-to-explore=128"}
87
88	hostOnlySanitizeFlags   = []string{"-fno-sanitize-recover=all"}
89	deviceOnlySanitizeFlags = []string{"-fsanitize-trap=all"}
90
91	noSanitizeLinkRuntimeFlag = "-fno-sanitize-link-runtime"
92)
93
94type SanitizerType int
95
96const (
97	Asan SanitizerType = iota + 1
98	Hwasan
99	tsan
100	intOverflow
101	scs
102	Fuzzer
103	Memtag_heap
104	Memtag_stack
105	Memtag_globals
106	cfi // cfi is last to prevent it running before incompatible mutators
107)
108
109var Sanitizers = []SanitizerType{
110	Asan,
111	Hwasan,
112	tsan,
113	intOverflow,
114	scs,
115	Fuzzer,
116	Memtag_heap,
117	Memtag_stack,
118	Memtag_globals,
119	cfi, // cfi is last to prevent it running before incompatible mutators
120}
121
122// Name of the sanitizer variation for this sanitizer type
123func (t SanitizerType) variationName() string {
124	switch t {
125	case Asan:
126		return "asan"
127	case Hwasan:
128		return "hwasan"
129	case tsan:
130		return "tsan"
131	case intOverflow:
132		return "intOverflow"
133	case cfi:
134		return "cfi"
135	case scs:
136		return "scs"
137	case Memtag_heap:
138		return "memtag_heap"
139	case Memtag_stack:
140		return "memtag_stack"
141	case Memtag_globals:
142		return "memtag_globals"
143	case Fuzzer:
144		return "fuzzer"
145	default:
146		panic(fmt.Errorf("unknown SanitizerType %d", t))
147	}
148}
149
150// This is the sanitizer names in SANITIZE_[TARGET|HOST]
151func (t SanitizerType) name() string {
152	switch t {
153	case Asan:
154		return "address"
155	case Hwasan:
156		return "hwaddress"
157	case Memtag_heap:
158		return "memtag_heap"
159	case Memtag_stack:
160		return "memtag_stack"
161	case Memtag_globals:
162		return "memtag_globals"
163	case tsan:
164		return "thread"
165	case intOverflow:
166		return "integer_overflow"
167	case cfi:
168		return "cfi"
169	case scs:
170		return "shadow-call-stack"
171	case Fuzzer:
172		return "fuzzer"
173	default:
174		panic(fmt.Errorf("unknown SanitizerType %d", t))
175	}
176}
177
178func (t SanitizerType) registerMutators(ctx android.RegisterMutatorsContext) {
179	switch t {
180	case cfi, Hwasan, Asan, tsan, Fuzzer, scs, Memtag_stack:
181		sanitizer := &sanitizerSplitMutator{t}
182		ctx.TopDown(t.variationName()+"_markapexes", sanitizer.markSanitizableApexesMutator)
183		ctx.Transition(t.variationName(), sanitizer)
184	case Memtag_heap, Memtag_globals, intOverflow:
185		// do nothing
186	default:
187		panic(fmt.Errorf("unknown SanitizerType %d", t))
188	}
189}
190
191// shouldPropagateToSharedLibraryDeps returns whether a sanitizer type should propagate to share
192// dependencies. In most cases, sanitizers only propagate to static dependencies; however, some
193// sanitizers also must be enabled for shared libraries for linking.
194func (t SanitizerType) shouldPropagateToSharedLibraryDeps() bool {
195	switch t {
196	case Fuzzer:
197		// Typically, shared libs are not split. However, for fuzzer, we split even for shared libs
198		// because a library sanitized for fuzzer can't be linked from a library that isn't sanitized
199		// for fuzzer.
200		return true
201	default:
202		return false
203	}
204}
205func (*Module) SanitizerSupported(t SanitizerType) bool {
206	switch t {
207	case Asan:
208		return true
209	case Hwasan:
210		return true
211	case tsan:
212		return true
213	case intOverflow:
214		return true
215	case cfi:
216		return true
217	case scs:
218		return true
219	case Fuzzer:
220		return true
221	case Memtag_heap:
222		return true
223	case Memtag_stack:
224		return true
225	case Memtag_globals:
226		return true
227	default:
228		return false
229	}
230}
231
232// incompatibleWithCfi returns true if a sanitizer is incompatible with CFI.
233func (t SanitizerType) incompatibleWithCfi() bool {
234	return t == Asan || t == Fuzzer || t == Hwasan
235}
236
237type SanitizeUserProps struct {
238	// Prevent use of any sanitizers on this module
239	Never *bool `android:"arch_variant"`
240
241	// ASan (Address sanitizer), incompatible with static binaries.
242	// Always runs in a diagnostic mode.
243	// Use of address sanitizer disables cfi sanitizer.
244	// Hwaddress sanitizer takes precedence over this sanitizer.
245	Address *bool `android:"arch_variant"`
246	// TSan (Thread sanitizer), incompatible with static binaries and 32 bit architectures.
247	// Always runs in a diagnostic mode.
248	// Use of thread sanitizer disables cfi and scudo sanitizers.
249	// Hwaddress sanitizer takes precedence over this sanitizer.
250	Thread *bool `android:"arch_variant"`
251	// HWASan (Hardware Address sanitizer).
252	// Use of hwasan sanitizer disables cfi, address, thread, and scudo sanitizers.
253	Hwaddress *bool `android:"arch_variant"`
254
255	// Undefined behavior sanitizer
256	All_undefined *bool `android:"arch_variant"`
257	// Subset of undefined behavior sanitizer
258	Undefined *bool `android:"arch_variant"`
259	// List of specific undefined behavior sanitizers to enable
260	Misc_undefined []string `android:"arch_variant"`
261	// Fuzzer, incompatible with static binaries.
262	Fuzzer *bool `android:"arch_variant"`
263	// safe-stack sanitizer, incompatible with 32-bit architectures.
264	Safestack *bool `android:"arch_variant"`
265	// cfi sanitizer, incompatible with asan, hwasan, fuzzer, or Darwin
266	Cfi *bool `android:"arch_variant"`
267	// signed/unsigned integer overflow sanitizer, incompatible with Darwin.
268	Integer_overflow *bool `android:"arch_variant"`
269	// scudo sanitizer, incompatible with asan, hwasan, tsan
270	// This should not be used in Android 11+ : https://source.android.com/devices/tech/debug/scudo
271	// deprecated
272	Scudo *bool `android:"arch_variant"`
273	// shadow-call-stack sanitizer, only available on arm64/riscv64.
274	Scs *bool `android:"arch_variant"`
275	// Memory-tagging, only available on arm64
276	// if diag.memtag unset or false, enables async memory tagging
277	Memtag_heap *bool `android:"arch_variant"`
278	// Memory-tagging stack instrumentation, only available on arm64
279	// Adds instrumentation to detect stack buffer overflows and use-after-scope using MTE.
280	Memtag_stack *bool `android:"arch_variant"`
281	// Memory-tagging globals instrumentation, only available on arm64
282	// Adds instrumentation to detect global buffer overflows using MTE.
283	Memtag_globals *bool `android:"arch_variant"`
284
285	// A modifier for ASAN and HWASAN for write only instrumentation
286	Writeonly *bool `android:"arch_variant"`
287
288	// Sanitizers to run in the diagnostic mode (as opposed to the release mode).
289	// Replaces abort() on error with a human-readable error message.
290	// Address and Thread sanitizers always run in diagnostic mode.
291	Diag struct {
292		// Undefined behavior sanitizer, diagnostic mode
293		Undefined *bool `android:"arch_variant"`
294		// cfi sanitizer, diagnostic mode, incompatible with asan, hwasan, fuzzer, or Darwin
295		Cfi *bool `android:"arch_variant"`
296		// signed/unsigned integer overflow sanitizer, diagnostic mode, incompatible with Darwin.
297		Integer_overflow *bool `android:"arch_variant"`
298		// Memory-tagging, only available on arm64
299		// requires sanitizer.memtag: true
300		// if set, enables sync memory tagging
301		Memtag_heap *bool `android:"arch_variant"`
302		// List of specific undefined behavior sanitizers to enable in diagnostic mode
303		Misc_undefined []string `android:"arch_variant"`
304		// List of sanitizers to pass to -fno-sanitize-recover
305		// results in only the first detected error for these sanitizers being reported and program then
306		// exits with a non-zero exit code.
307		No_recover []string `android:"arch_variant"`
308	} `android:"arch_variant"`
309
310	// Sanitizers to run with flag configuration specified
311	Config struct {
312		// Enables CFI support flags for assembly-heavy libraries
313		Cfi_assembly_support *bool `android:"arch_variant"`
314	} `android:"arch_variant"`
315
316	// List of sanitizers to pass to -fsanitize-recover
317	// allows execution to continue for these sanitizers to detect multiple errors rather than only
318	// the first one
319	Recover []string
320
321	// value to pass to -fsanitize-ignorelist
322	Blocklist *string
323}
324
325type sanitizeMutatedProperties struct {
326	// Whether sanitizers can be enabled on this module
327	Never *bool `blueprint:"mutated"`
328
329	// Whether ASan (Address sanitizer) is enabled for this module.
330	// Hwaddress sanitizer takes precedence over this sanitizer.
331	Address *bool `blueprint:"mutated"`
332	// Whether TSan (Thread sanitizer) is enabled for this module
333	Thread *bool `blueprint:"mutated"`
334	// Whether HWASan (Hardware Address sanitizer) is enabled for this module
335	Hwaddress *bool `blueprint:"mutated"`
336
337	// Whether Undefined behavior sanitizer is enabled for this module
338	All_undefined *bool `blueprint:"mutated"`
339	// Whether undefined behavior sanitizer subset is enabled for this module
340	Undefined *bool `blueprint:"mutated"`
341	// List of specific undefined behavior sanitizers enabled for this module
342	Misc_undefined []string `blueprint:"mutated"`
343	// Whether Fuzzeris enabled for this module
344	Fuzzer *bool `blueprint:"mutated"`
345	// whether safe-stack sanitizer is enabled for this module
346	Safestack *bool `blueprint:"mutated"`
347	// Whether cfi sanitizer is enabled for this module
348	Cfi *bool `blueprint:"mutated"`
349	// Whether signed/unsigned integer overflow sanitizer is enabled for this module
350	Integer_overflow *bool `blueprint:"mutated"`
351	// Whether scudo sanitizer is enabled for this module
352	Scudo *bool `blueprint:"mutated"`
353	// Whether shadow-call-stack sanitizer is enabled for this module.
354	Scs *bool `blueprint:"mutated"`
355	// Whether Memory-tagging is enabled for this module
356	Memtag_heap *bool `blueprint:"mutated"`
357	// Whether Memory-tagging stack instrumentation is enabled for this module
358	Memtag_stack *bool `blueprint:"mutated"`
359	// Whether Memory-tagging globals instrumentation is enabled for this module
360	Memtag_globals *bool `android:"arch_variant"`
361
362	// Whether a modifier for ASAN and HWASAN for write only instrumentation is enabled for this
363	// module
364	Writeonly *bool `blueprint:"mutated"`
365
366	// Sanitizers to run in the diagnostic mode (as opposed to the release mode).
367	Diag struct {
368		// Whether Undefined behavior sanitizer, diagnostic mode is enabled for this module
369		Undefined *bool `blueprint:"mutated"`
370		// Whether cfi sanitizer, diagnostic mode is enabled for this module
371		Cfi *bool `blueprint:"mutated"`
372		// Whether signed/unsigned integer overflow sanitizer, diagnostic mode is enabled for this
373		// module
374		Integer_overflow *bool `blueprint:"mutated"`
375		// Whether Memory-tagging, diagnostic mode is enabled for this module
376		Memtag_heap *bool `blueprint:"mutated"`
377		// List of specific undefined behavior sanitizers enabled in diagnostic mode
378		Misc_undefined []string `blueprint:"mutated"`
379	} `blueprint:"mutated"`
380}
381
382type SanitizeProperties struct {
383	Sanitize        SanitizeUserProps         `android:"arch_variant"`
384	SanitizeMutated sanitizeMutatedProperties `blueprint:"mutated"`
385
386	SanitizerEnabled  bool     `blueprint:"mutated"`
387	MinimalRuntimeDep bool     `blueprint:"mutated"`
388	BuiltinsDep       bool     `blueprint:"mutated"`
389	UbsanRuntimeDep   bool     `blueprint:"mutated"`
390	InSanitizerDir    bool     `blueprint:"mutated"`
391	Sanitizers        []string `blueprint:"mutated"`
392	DiagSanitizers    []string `blueprint:"mutated"`
393}
394
395type sanitize struct {
396	Properties SanitizeProperties
397}
398
399// Mark this tag with a check to see if apex dependency check should be skipped
400func (t libraryDependencyTag) SkipApexAllowedDependenciesCheck() bool {
401	return t.skipApexAllowedDependenciesCheck
402}
403
404var _ android.SkipApexAllowedDependenciesCheck = (*libraryDependencyTag)(nil)
405
406func init() {
407	pctx.StaticVariable("HostOnlySanitizeFlags", strings.Join(hostOnlySanitizeFlags, " "))
408
409	android.RegisterMakeVarsProvider(pctx, cfiMakeVarsProvider)
410	android.RegisterMakeVarsProvider(pctx, hwasanMakeVarsProvider)
411	android.RegisterMakeVarsProvider(pctx, memtagStackMakeVarsProvider)
412
413	RegisterSanitizerLibrariesTxtType(android.InitRegistrationContext)
414}
415
416func (sanitize *sanitize) props() []interface{} {
417	return []interface{}{&sanitize.Properties}
418}
419
420func (p *sanitizeMutatedProperties) copyUserPropertiesToMutated(userProps *SanitizeUserProps) {
421	p.Never = userProps.Never
422	p.Address = userProps.Address
423	p.All_undefined = userProps.All_undefined
424	p.Cfi = userProps.Cfi
425	p.Fuzzer = userProps.Fuzzer
426	p.Hwaddress = userProps.Hwaddress
427	p.Integer_overflow = userProps.Integer_overflow
428	p.Memtag_heap = userProps.Memtag_heap
429	p.Memtag_stack = userProps.Memtag_stack
430	p.Memtag_globals = userProps.Memtag_globals
431	p.Safestack = userProps.Safestack
432	p.Scs = userProps.Scs
433	p.Scudo = userProps.Scudo
434	p.Thread = userProps.Thread
435	p.Undefined = userProps.Undefined
436	p.Writeonly = userProps.Writeonly
437
438	p.Misc_undefined = make([]string, 0, len(userProps.Misc_undefined))
439	for _, v := range userProps.Misc_undefined {
440		p.Misc_undefined = append(p.Misc_undefined, v)
441	}
442
443	p.Diag.Cfi = userProps.Diag.Cfi
444	p.Diag.Integer_overflow = userProps.Diag.Integer_overflow
445	p.Diag.Memtag_heap = userProps.Diag.Memtag_heap
446	p.Diag.Undefined = userProps.Diag.Undefined
447
448	p.Diag.Misc_undefined = make([]string, 0, len(userProps.Diag.Misc_undefined))
449	for _, v := range userProps.Diag.Misc_undefined {
450		p.Diag.Misc_undefined = append(p.Diag.Misc_undefined, v)
451	}
452}
453
454func (sanitize *sanitize) begin(ctx BaseModuleContext) {
455	s := &sanitize.Properties.SanitizeMutated
456	s.copyUserPropertiesToMutated(&sanitize.Properties.Sanitize)
457
458	// Don't apply sanitizers to NDK code.
459	if ctx.useSdk() {
460		s.Never = BoolPtr(true)
461	}
462
463	// Never always wins.
464	if Bool(s.Never) {
465		return
466	}
467
468	// cc_test targets default to SYNC MemTag unless explicitly set to ASYNC (via diag: {memtag_heap: false}).
469	if ctx.testBinary() {
470		if s.Memtag_heap == nil {
471			s.Memtag_heap = proptools.BoolPtr(true)
472		}
473		if s.Diag.Memtag_heap == nil {
474			s.Diag.Memtag_heap = proptools.BoolPtr(true)
475		}
476	}
477
478	var globalSanitizers []string
479	var globalSanitizersDiag []string
480
481	if ctx.Host() {
482		if !ctx.Windows() {
483			globalSanitizers = ctx.Config().SanitizeHost()
484		}
485	} else {
486		arches := ctx.Config().SanitizeDeviceArch()
487		if len(arches) == 0 || inList(ctx.Arch().ArchType.Name, arches) {
488			globalSanitizers = ctx.Config().SanitizeDevice()
489			globalSanitizersDiag = ctx.Config().SanitizeDeviceDiag()
490		}
491	}
492
493	if len(globalSanitizers) > 0 {
494		var found bool
495		if found, globalSanitizers = removeFromList("undefined", globalSanitizers); found && s.All_undefined == nil {
496			s.All_undefined = proptools.BoolPtr(true)
497		}
498
499		if found, globalSanitizers = removeFromList("default-ub", globalSanitizers); found && s.Undefined == nil {
500			s.Undefined = proptools.BoolPtr(true)
501		}
502
503		if found, globalSanitizers = removeFromList("address", globalSanitizers); found && s.Address == nil {
504			s.Address = proptools.BoolPtr(true)
505		}
506
507		if found, globalSanitizers = removeFromList("thread", globalSanitizers); found && s.Thread == nil {
508			s.Thread = proptools.BoolPtr(true)
509		}
510
511		if found, globalSanitizers = removeFromList("fuzzer", globalSanitizers); found && s.Fuzzer == nil {
512			s.Fuzzer = proptools.BoolPtr(true)
513		}
514
515		if found, globalSanitizers = removeFromList("safe-stack", globalSanitizers); found && s.Safestack == nil {
516			s.Safestack = proptools.BoolPtr(true)
517		}
518
519		if found, globalSanitizers = removeFromList("cfi", globalSanitizers); found && s.Cfi == nil {
520			if !ctx.Config().CFIDisabledForPath(ctx.ModuleDir()) {
521				s.Cfi = proptools.BoolPtr(true)
522			}
523		}
524
525		// Global integer_overflow builds do not support static libraries.
526		if found, globalSanitizers = removeFromList("integer_overflow", globalSanitizers); found && s.Integer_overflow == nil {
527			if !ctx.Config().IntegerOverflowDisabledForPath(ctx.ModuleDir()) && !ctx.static() {
528				s.Integer_overflow = proptools.BoolPtr(true)
529			}
530		}
531
532		if found, globalSanitizers = removeFromList("scudo", globalSanitizers); found && s.Scudo == nil {
533			s.Scudo = proptools.BoolPtr(true)
534		}
535
536		if found, globalSanitizers = removeFromList("hwaddress", globalSanitizers); found && s.Hwaddress == nil {
537			if !ctx.Config().HWASanDisabledForPath(ctx.ModuleDir()) {
538				s.Hwaddress = proptools.BoolPtr(true)
539			}
540		}
541
542		if found, globalSanitizers = removeFromList("writeonly", globalSanitizers); found && s.Writeonly == nil {
543			// Hwaddress and Address are set before, so we can check them here
544			// If they aren't explicitly set in the blueprint/SANITIZE_(HOST|TARGET), they would be nil instead of false
545			if s.Address == nil && s.Hwaddress == nil {
546				ctx.ModuleErrorf("writeonly modifier cannot be used without 'address' or 'hwaddress'")
547			}
548			s.Writeonly = proptools.BoolPtr(true)
549		}
550		if found, globalSanitizers = removeFromList("memtag_heap", globalSanitizers); found && s.Memtag_heap == nil {
551			if !ctx.Config().MemtagHeapDisabledForPath(ctx.ModuleDir()) {
552				s.Memtag_heap = proptools.BoolPtr(true)
553			}
554		}
555
556		if found, globalSanitizers = removeFromList("memtag_stack", globalSanitizers); found && s.Memtag_stack == nil {
557			s.Memtag_stack = proptools.BoolPtr(true)
558		}
559
560		if found, globalSanitizers = removeFromList("memtag_globals", globalSanitizers); found && s.Memtag_globals == nil {
561			s.Memtag_globals = proptools.BoolPtr(true)
562		}
563
564		if len(globalSanitizers) > 0 {
565			ctx.ModuleErrorf("unknown global sanitizer option %s", globalSanitizers[0])
566		}
567
568		// Global integer_overflow builds do not support static library diagnostics.
569		if found, globalSanitizersDiag = removeFromList("integer_overflow", globalSanitizersDiag); found &&
570			s.Diag.Integer_overflow == nil && Bool(s.Integer_overflow) && !ctx.static() {
571			s.Diag.Integer_overflow = proptools.BoolPtr(true)
572		}
573
574		if found, globalSanitizersDiag = removeFromList("cfi", globalSanitizersDiag); found &&
575			s.Diag.Cfi == nil && Bool(s.Cfi) {
576			s.Diag.Cfi = proptools.BoolPtr(true)
577		}
578
579		if found, globalSanitizersDiag = removeFromList("memtag_heap", globalSanitizersDiag); found &&
580			s.Diag.Memtag_heap == nil && Bool(s.Memtag_heap) {
581			s.Diag.Memtag_heap = proptools.BoolPtr(true)
582		}
583
584		if len(globalSanitizersDiag) > 0 {
585			ctx.ModuleErrorf("unknown global sanitizer diagnostics option %s", globalSanitizersDiag[0])
586		}
587	}
588
589	// Enable Memtag for all components in the include paths (for Aarch64 only)
590	if ctx.Arch().ArchType == android.Arm64 && ctx.toolchain().Bionic() {
591		if ctx.Config().MemtagHeapSyncEnabledForPath(ctx.ModuleDir()) {
592			if s.Memtag_heap == nil {
593				s.Memtag_heap = proptools.BoolPtr(true)
594			}
595			if s.Diag.Memtag_heap == nil {
596				s.Diag.Memtag_heap = proptools.BoolPtr(true)
597			}
598		} else if ctx.Config().MemtagHeapAsyncEnabledForPath(ctx.ModuleDir()) {
599			if s.Memtag_heap == nil {
600				s.Memtag_heap = proptools.BoolPtr(true)
601			}
602		}
603	}
604
605	// Enable HWASan for all components in the include paths (for Aarch64 only)
606	if s.Hwaddress == nil && ctx.Config().HWASanEnabledForPath(ctx.ModuleDir()) &&
607		ctx.Arch().ArchType == android.Arm64 && ctx.toolchain().Bionic() {
608		s.Hwaddress = proptools.BoolPtr(true)
609	}
610
611	// Enable CFI for non-host components in the include paths
612	if s.Cfi == nil && ctx.Config().CFIEnabledForPath(ctx.ModuleDir()) && !ctx.Host() {
613		s.Cfi = proptools.BoolPtr(true)
614		if inList("cfi", ctx.Config().SanitizeDeviceDiag()) {
615			s.Diag.Cfi = proptools.BoolPtr(true)
616		}
617	}
618
619	// Is CFI actually enabled?
620	if !ctx.Config().EnableCFI() {
621		s.Cfi = nil
622		s.Diag.Cfi = nil
623	}
624
625	// HWASan requires AArch64 hardware feature (top-byte-ignore).
626	if ctx.Arch().ArchType != android.Arm64 || !ctx.toolchain().Bionic() {
627		s.Hwaddress = nil
628	}
629
630	// SCS is only implemented on AArch64/riscv64.
631	if (ctx.Arch().ArchType != android.Arm64 && ctx.Arch().ArchType != android.Riscv64) || !ctx.toolchain().Bionic() {
632		s.Scs = nil
633	}
634
635	// Memtag_heap is only implemented on AArch64.
636	// Memtag ABI is Android specific for now, so disable for host.
637	if ctx.Arch().ArchType != android.Arm64 || !ctx.toolchain().Bionic() || ctx.Host() {
638		s.Memtag_heap = nil
639		s.Memtag_stack = nil
640		s.Memtag_globals = nil
641	}
642
643	// Also disable CFI if ASAN is enabled.
644	if Bool(s.Address) || Bool(s.Hwaddress) {
645		s.Cfi = nil
646		s.Diag.Cfi = nil
647		// HWASAN and ASAN win against MTE.
648		s.Memtag_heap = nil
649		s.Memtag_stack = nil
650		s.Memtag_globals = nil
651	}
652
653	// Disable sanitizers that depend on the UBSan runtime for windows/darwin builds.
654	if !ctx.Os().Linux() {
655		s.Cfi = nil
656		s.Diag.Cfi = nil
657		s.Misc_undefined = nil
658		s.Undefined = nil
659		s.All_undefined = nil
660		s.Integer_overflow = nil
661	}
662
663	// Disable CFI for musl
664	if ctx.toolchain().Musl() {
665		s.Cfi = nil
666		s.Diag.Cfi = nil
667	}
668
669	// TODO(b/280478629): runtimes don't exist for musl arm64 yet.
670	if ctx.toolchain().Musl() && ctx.Arch().ArchType == android.Arm64 {
671		s.Address = nil
672		s.Hwaddress = nil
673		s.Thread = nil
674		s.Scudo = nil
675		s.Fuzzer = nil
676		s.Cfi = nil
677		s.Diag.Cfi = nil
678		s.Misc_undefined = nil
679		s.Undefined = nil
680		s.All_undefined = nil
681		s.Integer_overflow = nil
682	}
683
684	if ctx.inRamdisk() || ctx.inVendorRamdisk() || ctx.inRecovery() {
685		// HWASan ramdisk (which is built from recovery) goes over some bootloader limit.
686		// Keep libc instrumented so that ramdisk / vendor_ramdisk / recovery can run hwasan-instrumented code if necessary.
687		if !strings.HasPrefix(ctx.ModuleDir(), "bionic/libc") {
688			s.Hwaddress = nil
689		}
690		// Memtag stack in ramdisk makes pKVM unhappy.
691		s.Memtag_stack = nil
692	}
693
694	if ctx.staticBinary() {
695		s.Address = nil
696		s.Fuzzer = nil
697		s.Thread = nil
698	}
699
700	if Bool(s.All_undefined) {
701		s.Undefined = nil
702	}
703
704	if !ctx.toolchain().Is64Bit() {
705		// TSAN and SafeStack are not supported on 32-bit architectures
706		s.Thread = nil
707		s.Safestack = nil
708		// TODO(ccross): error for compile_multilib = "32"?
709	}
710
711	if ctx.Os() != android.Windows && (Bool(s.All_undefined) || Bool(s.Undefined) || Bool(s.Address) || Bool(s.Thread) ||
712		Bool(s.Fuzzer) || Bool(s.Safestack) || Bool(s.Cfi) || Bool(s.Integer_overflow) || len(s.Misc_undefined) > 0 ||
713		Bool(s.Scudo) || Bool(s.Hwaddress) || Bool(s.Scs) || Bool(s.Memtag_heap) || Bool(s.Memtag_stack) ||
714		Bool(s.Memtag_globals)) {
715		sanitize.Properties.SanitizerEnabled = true
716	}
717
718	// Disable Scudo if ASan or TSan is enabled, or if it's disabled globally.
719	if Bool(s.Address) || Bool(s.Thread) || Bool(s.Hwaddress) || ctx.Config().DisableScudo() {
720		s.Scudo = nil
721	}
722
723	if Bool(s.Hwaddress) {
724		s.Address = nil
725		s.Thread = nil
726	}
727
728	// TODO(b/131771163): CFI transiently depends on LTO, and thus Fuzzer is
729	// mutually incompatible.
730	if Bool(s.Fuzzer) {
731		s.Cfi = nil
732	}
733}
734
735func toDisableImplicitIntegerChange(flags []string) bool {
736	// Returns true if any flag is fsanitize*integer, and there is
737	// no explicit flag about sanitize=implicit-integer-sign-change.
738	for _, f := range flags {
739		if strings.Contains(f, "sanitize=implicit-integer-sign-change") {
740			return false
741		}
742	}
743	for _, f := range flags {
744		if strings.HasPrefix(f, "-fsanitize") && strings.Contains(f, "integer") {
745			return true
746		}
747	}
748	return false
749}
750
751func toDisableUnsignedShiftBaseChange(flags []string) bool {
752	// Returns true if any flag is fsanitize*integer, and there is
753	// no explicit flag about sanitize=unsigned-shift-base.
754	for _, f := range flags {
755		if strings.Contains(f, "sanitize=unsigned-shift-base") {
756			return false
757		}
758	}
759	for _, f := range flags {
760		if strings.HasPrefix(f, "-fsanitize") && strings.Contains(f, "integer") {
761			return true
762		}
763	}
764	return false
765}
766
767func (s *sanitize) flags(ctx ModuleContext, flags Flags) Flags {
768	if !s.Properties.SanitizerEnabled && !s.Properties.UbsanRuntimeDep {
769		return flags
770	}
771	sanProps := &s.Properties.SanitizeMutated
772
773	if Bool(sanProps.Address) {
774		if ctx.Arch().ArchType == android.Arm {
775			// Frame pointer based unwinder in ASan requires ARM frame setup.
776			// TODO: put in flags?
777			flags.RequiredInstructionSet = "arm"
778		}
779		flags.Local.CFlags = append(flags.Local.CFlags, asanCflags...)
780		flags.Local.LdFlags = append(flags.Local.LdFlags, asanLdflags...)
781
782		if Bool(sanProps.Writeonly) {
783			flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm", "-asan-instrument-reads=0")
784		}
785
786		if ctx.Host() {
787			// -nodefaultlibs (provided with libc++) prevents the driver from linking
788			// libraries needed with -fsanitize=address. http://b/18650275 (WAI)
789			flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--no-as-needed")
790		} else {
791			flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm", "-asan-globals=0")
792			if ctx.bootstrap() {
793				flags.DynamicLinker = "/system/bin/bootstrap/linker_asan"
794			} else {
795				flags.DynamicLinker = "/system/bin/linker_asan"
796			}
797			if flags.Toolchain.Is64Bit() {
798				flags.DynamicLinker += "64"
799			}
800		}
801	}
802
803	if Bool(sanProps.Hwaddress) {
804		flags.Local.CFlags = append(flags.Local.CFlags, hwasanCflags...)
805
806		for _, flag := range hwasanCommonflags {
807			flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm", flag)
808		}
809		for _, flag := range hwasanCommonflags {
810			flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-mllvm,"+flag)
811		}
812
813		if Bool(sanProps.Writeonly) {
814			flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm", "-hwasan-instrument-reads=0")
815		}
816		if !ctx.staticBinary() && !ctx.Host() {
817			if ctx.bootstrap() {
818				flags.DynamicLinker = "/system/bin/bootstrap/linker_hwasan64"
819			} else {
820				flags.DynamicLinker = "/system/bin/linker_hwasan64"
821			}
822		}
823	}
824
825	if Bool(sanProps.Fuzzer) {
826		flags.Local.CFlags = append(flags.Local.CFlags, "-fsanitize=fuzzer-no-link")
827
828		// TODO(b/131771163): LTO and Fuzzer support is mutually incompatible.
829		_, flags.Local.LdFlags = removeFromList("-flto", flags.Local.LdFlags)
830		_, flags.Local.CFlags = removeFromList("-flto", flags.Local.CFlags)
831		flags.Local.LdFlags = append(flags.Local.LdFlags, "-fno-lto")
832		flags.Local.CFlags = append(flags.Local.CFlags, "-fno-lto")
833
834		// TODO(b/142430592): Upstream linker scripts for sanitizer runtime libraries
835		// discard the sancov_lowest_stack symbol, because it's emulated TLS (and thus
836		// doesn't match the linker script due to the "__emutls_v." prefix).
837		flags.Local.LdFlags = append(flags.Local.LdFlags, "-fno-sanitize-coverage=stack-depth")
838		flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize-coverage=stack-depth")
839
840		// Disable fortify for fuzzing builds. Generally, we'll be building with
841		// UBSan or ASan here and the fortify checks pollute the stack traces.
842		flags.Local.CFlags = append(flags.Local.CFlags, "-U_FORTIFY_SOURCE")
843
844		// Build fuzzer-sanitized libraries with an $ORIGIN DT_RUNPATH. Android's
845		// linker uses DT_RUNPATH, not DT_RPATH. When we deploy cc_fuzz targets and
846		// their libraries to /data/fuzz/<arch>/lib, any transient shared library gets
847		// the DT_RUNPATH from the shared library above it, and not the executable,
848		// meaning that the lookup falls back to the system. Adding the $ORIGIN to the
849		// DT_RUNPATH here means that transient shared libraries can be found
850		// colocated with their parents.
851		flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN`)
852	}
853
854	if Bool(sanProps.Cfi) {
855		if ctx.Arch().ArchType == android.Arm {
856			// __cfi_check needs to be built as Thumb (see the code in linker_cfi.cpp). LLVM is not set up
857			// to do this on a function basis, so force Thumb on the entire module.
858			flags.RequiredInstructionSet = "thumb"
859		}
860
861		flags.Local.CFlags = append(flags.Local.CFlags, cfiCflags...)
862		flags.Local.AsFlags = append(flags.Local.AsFlags, cfiAsflags...)
863		flags.CFlagsDeps = append(flags.CFlagsDeps, android.PathForSource(ctx, cfiBlocklistPath+"/"+cfiBlocklistFilename))
864		if Bool(s.Properties.Sanitize.Config.Cfi_assembly_support) {
865			flags.Local.CFlags = append(flags.Local.CFlags, cfiAssemblySupportFlag)
866		}
867		// Only append the default visibility flag if -fvisibility has not already been set
868		// to hidden.
869		if !inList("-fvisibility=hidden", flags.Local.CFlags) {
870			flags.Local.CFlags = append(flags.Local.CFlags, "-fvisibility=default")
871		}
872		flags.Local.LdFlags = append(flags.Local.LdFlags, cfiLdflags...)
873
874		if ctx.staticBinary() {
875			_, flags.Local.CFlags = removeFromList("-fsanitize-cfi-cross-dso", flags.Local.CFlags)
876			_, flags.Local.LdFlags = removeFromList("-fsanitize-cfi-cross-dso", flags.Local.LdFlags)
877		}
878	}
879
880	if Bool(sanProps.Memtag_stack) {
881		flags.Local.CFlags = append(flags.Local.CFlags, memtagStackCommonFlags...)
882		flags.Local.AsFlags = append(flags.Local.AsFlags, memtagStackCommonFlags...)
883		flags.Local.LdFlags = append(flags.Local.LdFlags, memtagStackCommonFlags...)
884
885		for _, flag := range memtagStackLlvmFlags {
886			flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm", flag)
887		}
888		for _, flag := range memtagStackLlvmFlags {
889			flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-mllvm,"+flag)
890		}
891	}
892
893	if (Bool(sanProps.Memtag_heap) || Bool(sanProps.Memtag_stack) || Bool(sanProps.Memtag_globals)) && ctx.binary() {
894		if Bool(sanProps.Diag.Memtag_heap) {
895			flags.Local.LdFlags = append(flags.Local.LdFlags, "-fsanitize-memtag-mode=sync")
896		} else {
897			flags.Local.LdFlags = append(flags.Local.LdFlags, "-fsanitize-memtag-mode=async")
898		}
899	}
900
901	if Bool(sanProps.Integer_overflow) {
902		flags.Local.CFlags = append(flags.Local.CFlags, intOverflowCflags...)
903	}
904
905	if len(s.Properties.Sanitizers) > 0 {
906		sanitizeArg := "-fsanitize=" + strings.Join(s.Properties.Sanitizers, ",")
907		flags.Local.CFlags = append(flags.Local.CFlags, sanitizeArg)
908		flags.Local.AsFlags = append(flags.Local.AsFlags, sanitizeArg)
909		flags.Local.LdFlags = append(flags.Local.LdFlags, sanitizeArg)
910
911		if ctx.toolchain().Bionic() || ctx.toolchain().Musl() {
912			// Bionic and musl sanitizer runtimes have already been added as dependencies so that
913			// the right variant of the runtime will be used (with the "-android" or "-musl"
914			// suffixes), so don't let clang the runtime library.
915			flags.Local.LdFlags = append(flags.Local.LdFlags, noSanitizeLinkRuntimeFlag)
916		} else {
917			// Host sanitizers only link symbols in the final executable, so
918			// there will always be undefined symbols in intermediate libraries.
919			_, flags.Global.LdFlags = removeFromList("-Wl,--no-undefined", flags.Global.LdFlags)
920		}
921
922		if !ctx.toolchain().Bionic() {
923			// non-Bionic toolchain prebuilts are missing UBSan's vptr and function san.
924			// Musl toolchain prebuilts have vptr and function sanitizers, but enabling them
925			// implicitly enables RTTI which causes RTTI mismatch issues with dependencies.
926
927			flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize=vptr,function")
928		}
929
930		if Bool(sanProps.Fuzzer) {
931			// When fuzzing, we wish to crash with diagnostics on any bug.
932			flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize-trap=all", "-fno-sanitize-recover=all")
933		} else if ctx.Host() {
934			flags.Local.CFlags = append(flags.Local.CFlags, hostOnlySanitizeFlags...)
935		} else {
936			flags.Local.CFlags = append(flags.Local.CFlags, deviceOnlySanitizeFlags...)
937		}
938
939		if enableMinimalRuntime(s) {
940			flags.Local.CFlags = append(flags.Local.CFlags, strings.Join(minimalRuntimeFlags, " "))
941		}
942
943		// http://b/119329758, Android core does not boot up with this sanitizer yet.
944		if toDisableImplicitIntegerChange(flags.Local.CFlags) {
945			flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize=implicit-integer-sign-change")
946		}
947		// http://b/171275751, Android doesn't build with this sanitizer yet.
948		if toDisableUnsignedShiftBaseChange(flags.Local.CFlags) {
949			flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize=unsigned-shift-base")
950		}
951	}
952
953	if len(s.Properties.DiagSanitizers) > 0 {
954		flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize-trap="+strings.Join(s.Properties.DiagSanitizers, ","))
955	}
956	// FIXME: enable RTTI if diag + (cfi or vptr)
957
958	if s.Properties.Sanitize.Recover != nil {
959		flags.Local.CFlags = append(flags.Local.CFlags, "-fsanitize-recover="+
960			strings.Join(s.Properties.Sanitize.Recover, ","))
961	}
962
963	if s.Properties.Sanitize.Diag.No_recover != nil {
964		flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize-recover="+
965			strings.Join(s.Properties.Sanitize.Diag.No_recover, ","))
966	}
967
968	blocklist := android.OptionalPathForModuleSrc(ctx, s.Properties.Sanitize.Blocklist)
969	if blocklist.Valid() {
970		flags.Local.CFlags = append(flags.Local.CFlags, sanitizeIgnorelistPrefix+blocklist.String())
971		flags.CFlagsDeps = append(flags.CFlagsDeps, blocklist.Path())
972	}
973
974	return flags
975}
976
977func (s *sanitize) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
978	// Add a suffix for cfi/hwasan/scs-enabled static/header libraries to allow surfacing
979	// both the sanitized and non-sanitized variants to make without a name conflict.
980	if entries.Class == "STATIC_LIBRARIES" || entries.Class == "HEADER_LIBRARIES" {
981		if Bool(s.Properties.SanitizeMutated.Cfi) {
982			entries.SubName += ".cfi"
983		}
984		if Bool(s.Properties.SanitizeMutated.Hwaddress) {
985			entries.SubName += ".hwasan"
986		}
987		if Bool(s.Properties.SanitizeMutated.Scs) {
988			entries.SubName += ".scs"
989		}
990	}
991}
992
993func (s *sanitize) inSanitizerDir() bool {
994	return s.Properties.InSanitizerDir
995}
996
997// getSanitizerBoolPtr returns the SanitizerTypes associated bool pointer from SanitizeProperties.
998func (s *sanitize) getSanitizerBoolPtr(t SanitizerType) *bool {
999	switch t {
1000	case Asan:
1001		return s.Properties.SanitizeMutated.Address
1002	case Hwasan:
1003		return s.Properties.SanitizeMutated.Hwaddress
1004	case tsan:
1005		return s.Properties.SanitizeMutated.Thread
1006	case intOverflow:
1007		return s.Properties.SanitizeMutated.Integer_overflow
1008	case cfi:
1009		return s.Properties.SanitizeMutated.Cfi
1010	case scs:
1011		return s.Properties.SanitizeMutated.Scs
1012	case Memtag_heap:
1013		return s.Properties.SanitizeMutated.Memtag_heap
1014	case Memtag_stack:
1015		return s.Properties.SanitizeMutated.Memtag_stack
1016	case Memtag_globals:
1017		return s.Properties.SanitizeMutated.Memtag_globals
1018	case Fuzzer:
1019		return s.Properties.SanitizeMutated.Fuzzer
1020	default:
1021		panic(fmt.Errorf("unknown SanitizerType %d", t))
1022	}
1023}
1024
1025// isUnsanitizedVariant returns true if no sanitizers are enabled.
1026func (sanitize *sanitize) isUnsanitizedVariant() bool {
1027	return !sanitize.isSanitizerEnabled(Asan) &&
1028		!sanitize.isSanitizerEnabled(Hwasan) &&
1029		!sanitize.isSanitizerEnabled(tsan) &&
1030		!sanitize.isSanitizerEnabled(cfi) &&
1031		!sanitize.isSanitizerEnabled(scs) &&
1032		!sanitize.isSanitizerEnabled(Memtag_heap) &&
1033		!sanitize.isSanitizerEnabled(Memtag_stack) &&
1034		!sanitize.isSanitizerEnabled(Memtag_globals) &&
1035		!sanitize.isSanitizerEnabled(Fuzzer)
1036}
1037
1038// isVariantOnProductionDevice returns true if variant is for production devices (no non-production sanitizers enabled).
1039func (sanitize *sanitize) isVariantOnProductionDevice() bool {
1040	return !sanitize.isSanitizerEnabled(Asan) &&
1041		!sanitize.isSanitizerEnabled(Hwasan) &&
1042		!sanitize.isSanitizerEnabled(tsan) &&
1043		!sanitize.isSanitizerEnabled(Fuzzer)
1044}
1045
1046func (sanitize *sanitize) SetSanitizer(t SanitizerType, b bool) {
1047	bPtr := proptools.BoolPtr(b)
1048	if !b {
1049		bPtr = nil
1050	}
1051	switch t {
1052	case Asan:
1053		sanitize.Properties.SanitizeMutated.Address = bPtr
1054		// For ASAN variant, we need to disable Memtag_stack
1055		sanitize.Properties.SanitizeMutated.Memtag_stack = nil
1056		sanitize.Properties.SanitizeMutated.Memtag_globals = nil
1057	case Hwasan:
1058		sanitize.Properties.SanitizeMutated.Hwaddress = bPtr
1059		// For HWAsan variant, we need to disable Memtag_stack
1060		sanitize.Properties.SanitizeMutated.Memtag_stack = nil
1061		sanitize.Properties.SanitizeMutated.Memtag_globals = nil
1062	case tsan:
1063		sanitize.Properties.SanitizeMutated.Thread = bPtr
1064	case intOverflow:
1065		sanitize.Properties.SanitizeMutated.Integer_overflow = bPtr
1066	case cfi:
1067		sanitize.Properties.SanitizeMutated.Cfi = bPtr
1068	case scs:
1069		sanitize.Properties.SanitizeMutated.Scs = bPtr
1070	case Memtag_heap:
1071		sanitize.Properties.SanitizeMutated.Memtag_heap = bPtr
1072	case Memtag_stack:
1073		sanitize.Properties.SanitizeMutated.Memtag_stack = bPtr
1074		// We do not need to disable ASAN or HWASan here, as there is no Memtag_stack variant.
1075	case Memtag_globals:
1076		sanitize.Properties.Sanitize.Memtag_globals = bPtr
1077	case Fuzzer:
1078		sanitize.Properties.SanitizeMutated.Fuzzer = bPtr
1079	default:
1080		panic(fmt.Errorf("unknown SanitizerType %d", t))
1081	}
1082	if b {
1083		sanitize.Properties.SanitizerEnabled = true
1084	}
1085}
1086
1087// Check if the sanitizer is explicitly disabled (as opposed to nil by
1088// virtue of not being set).
1089func (sanitize *sanitize) isSanitizerExplicitlyDisabled(t SanitizerType) bool {
1090	if sanitize == nil {
1091		return false
1092	}
1093
1094	sanitizerVal := sanitize.getSanitizerBoolPtr(t)
1095	return sanitizerVal != nil && *sanitizerVal == false
1096}
1097
1098// There isn't an analog of the method above (ie:isSanitizerExplicitlyEnabled)
1099// because enabling a sanitizer either directly (via the blueprint) or
1100// indirectly (via a mutator) sets the bool ptr to true, and you can't
1101// distinguish between the cases. It isn't needed though - both cases can be
1102// treated identically.
1103func (s *sanitize) isSanitizerEnabled(t SanitizerType) bool {
1104	if s == nil {
1105		return false
1106	}
1107	if proptools.Bool(s.Properties.SanitizeMutated.Never) {
1108		return false
1109	}
1110
1111	sanitizerVal := s.getSanitizerBoolPtr(t)
1112	return sanitizerVal != nil && *sanitizerVal == true
1113}
1114
1115// IsSanitizableDependencyTag returns true if the dependency tag is sanitizable.
1116func IsSanitizableDependencyTag(tag blueprint.DependencyTag) bool {
1117	switch t := tag.(type) {
1118	case dependencyTag:
1119		return t == reuseObjTag || t == objDepTag
1120	case libraryDependencyTag:
1121		return true
1122	default:
1123		return false
1124	}
1125}
1126
1127func (m *Module) SanitizableDepTagChecker() SantizableDependencyTagChecker {
1128	return IsSanitizableDependencyTag
1129}
1130
1131type sanitizerSplitMutator struct {
1132	sanitizer SanitizerType
1133}
1134
1135// If an APEX is sanitized or not depends on whether it contains at least one
1136// sanitized module. Transition mutators cannot propagate information up the
1137// dependency graph this way, so we need an auxiliary mutator to do so.
1138func (s *sanitizerSplitMutator) markSanitizableApexesMutator(ctx android.TopDownMutatorContext) {
1139	if sanitizeable, ok := ctx.Module().(Sanitizeable); ok {
1140		enabled := sanitizeable.IsSanitizerEnabled(ctx.Config(), s.sanitizer.name())
1141		ctx.VisitDirectDeps(func(dep android.Module) {
1142			if c, ok := dep.(PlatformSanitizeable); ok && c.IsSanitizerEnabled(s.sanitizer) {
1143				enabled = true
1144			}
1145		})
1146
1147		if enabled {
1148			sanitizeable.EnableSanitizer(s.sanitizer.name())
1149		}
1150	}
1151}
1152
1153func (s *sanitizerSplitMutator) Split(ctx android.BaseModuleContext) []string {
1154	if c, ok := ctx.Module().(PlatformSanitizeable); ok && c.SanitizePropDefined() {
1155		// If the given sanitizer is not requested in the .bp file for a module, it
1156		// won't automatically build the sanitized variation.
1157		if !c.IsSanitizerEnabled(s.sanitizer) {
1158			return []string{""}
1159		}
1160
1161		if c.Binary() {
1162			// If a sanitizer is enabled for a binary, we do not build the version
1163			// without the sanitizer
1164			return []string{s.sanitizer.variationName()}
1165		} else if c.StaticallyLinked() || c.Header() {
1166			// For static libraries, we build both versions. Some Make modules
1167			// apparently depend on this behavior.
1168			return []string{"", s.sanitizer.variationName()}
1169		} else {
1170			// We only build the requested variation of dynamic libraries
1171			return []string{s.sanitizer.variationName()}
1172		}
1173	}
1174
1175	if _, ok := ctx.Module().(JniSanitizeable); ok {
1176		// TODO: this should call into JniSanitizable.IsSanitizerEnabledForJni but
1177		// that is short-circuited for now
1178		return []string{""}
1179	}
1180
1181	// If an APEX has a sanitized dependency, we build the APEX in the sanitized
1182	// variation. This is useful because such APEXes require extra dependencies.
1183	if sanitizeable, ok := ctx.Module().(Sanitizeable); ok {
1184		enabled := sanitizeable.IsSanitizerEnabled(ctx.Config(), s.sanitizer.name())
1185		if enabled {
1186			return []string{s.sanitizer.variationName()}
1187		} else {
1188			return []string{""}
1189		}
1190	}
1191
1192	return []string{""}
1193}
1194
1195func (s *sanitizerSplitMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
1196	if c, ok := ctx.Module().(PlatformSanitizeable); ok {
1197		if !c.SanitizableDepTagChecker()(ctx.DepTag()) {
1198			// If the dependency is through a non-sanitizable tag, use the
1199			// non-sanitized variation
1200			return ""
1201		}
1202
1203		return sourceVariation
1204	} else if _, ok := ctx.Module().(JniSanitizeable); ok {
1205		// TODO: this should call into JniSanitizable.IsSanitizerEnabledForJni but
1206		// that is short-circuited for now
1207		return ""
1208	} else {
1209		// Otherwise, do not rock the boat.
1210		return sourceVariation
1211	}
1212}
1213
1214func (s *sanitizerSplitMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
1215	if d, ok := ctx.Module().(PlatformSanitizeable); ok {
1216		if !d.SanitizePropDefined() ||
1217			d.SanitizeNever() ||
1218			d.IsSanitizerExplicitlyDisabled(s.sanitizer) ||
1219			!d.SanitizerSupported(s.sanitizer) {
1220			// If a module opts out of a sanitizer, use its non-sanitized variation
1221			return ""
1222		}
1223
1224		// Binaries are always built in the variation they requested.
1225		if d.Binary() {
1226			if d.IsSanitizerEnabled(s.sanitizer) {
1227				return s.sanitizer.variationName()
1228			} else {
1229				return ""
1230			}
1231		}
1232
1233		// If a shared library requests to be sanitized, it will be built for that
1234		// sanitizer. Otherwise, some sanitizers propagate through shared library
1235		// dependency edges, some do not.
1236		if !d.StaticallyLinked() && !d.Header() {
1237			if d.IsSanitizerEnabled(s.sanitizer) {
1238				return s.sanitizer.variationName()
1239			}
1240
1241			// Some sanitizers do not propagate to shared dependencies
1242			if !s.sanitizer.shouldPropagateToSharedLibraryDeps() {
1243				return ""
1244			}
1245		}
1246
1247		// Static and header libraries inherit whether they are sanitized from the
1248		// module they are linked into
1249		return incomingVariation
1250	} else if d, ok := ctx.Module().(Sanitizeable); ok {
1251		// If an APEX contains a sanitized module, it will be built in the variation
1252		// corresponding to that sanitizer.
1253		enabled := d.IsSanitizerEnabled(ctx.Config(), s.sanitizer.name())
1254		if enabled {
1255			return s.sanitizer.variationName()
1256		}
1257
1258		return incomingVariation
1259	}
1260
1261	return ""
1262}
1263
1264func (s *sanitizerSplitMutator) Mutate(mctx android.BottomUpMutatorContext, variationName string) {
1265	sanitizerVariation := variationName == s.sanitizer.variationName()
1266
1267	if c, ok := mctx.Module().(PlatformSanitizeable); ok && c.SanitizePropDefined() {
1268		sanitizerEnabled := c.IsSanitizerEnabled(s.sanitizer)
1269
1270		oneMakeVariation := false
1271		if c.StaticallyLinked() || c.Header() {
1272			if s.sanitizer != cfi && s.sanitizer != scs && s.sanitizer != Hwasan {
1273				// These sanitizers export only one variation to Make. For the rest,
1274				// Make targets can depend on both the sanitized and non-sanitized
1275				// versions.
1276				oneMakeVariation = true
1277			}
1278		} else if !c.Binary() {
1279			// Shared library. These are the sanitizers that do propagate through shared
1280			// library dependencies and therefore can cause multiple variations of a
1281			// shared library to be built.
1282			if s.sanitizer != cfi && s.sanitizer != Hwasan && s.sanitizer != scs && s.sanitizer != Asan {
1283				oneMakeVariation = true
1284			}
1285		}
1286
1287		if oneMakeVariation {
1288			if sanitizerEnabled != sanitizerVariation {
1289				c.SetPreventInstall()
1290				c.SetHideFromMake()
1291			}
1292		}
1293
1294		if sanitizerVariation {
1295			c.SetSanitizer(s.sanitizer, true)
1296
1297			// CFI is incompatible with ASAN so disable it in ASAN variations
1298			if s.sanitizer.incompatibleWithCfi() {
1299				cfiSupported := mctx.Module().(PlatformSanitizeable).SanitizerSupported(cfi)
1300				if mctx.Device() && cfiSupported {
1301					c.SetSanitizer(cfi, false)
1302				}
1303			}
1304
1305			// locate the asan libraries under /data/asan
1306			if !c.Binary() && !c.StaticallyLinked() && !c.Header() && mctx.Device() && s.sanitizer == Asan && sanitizerEnabled {
1307				c.SetInSanitizerDir()
1308			}
1309
1310			if c.StaticallyLinked() && c.ExportedToMake() {
1311				if s.sanitizer == Hwasan {
1312					hwasanStaticLibs(mctx.Config()).add(c, c.Module().Name())
1313				} else if s.sanitizer == cfi {
1314					cfiStaticLibs(mctx.Config()).add(c, c.Module().Name())
1315				} else if s.sanitizer == Memtag_stack {
1316					memtagStackStaticLibs(mctx.Config()).add(c, c.Module().Name())
1317				}
1318			}
1319		} else if c.IsSanitizerEnabled(s.sanitizer) {
1320			// Disable the sanitizer for the non-sanitized variation
1321			c.SetSanitizer(s.sanitizer, false)
1322		}
1323	} else if sanitizeable, ok := mctx.Module().(Sanitizeable); ok {
1324		// If an APEX has sanitized dependencies, it gets a few more dependencies
1325		if sanitizerVariation {
1326			sanitizeable.AddSanitizerDependencies(mctx, s.sanitizer.name())
1327		}
1328	}
1329}
1330
1331func (c *Module) SanitizeNever() bool {
1332	return Bool(c.sanitize.Properties.SanitizeMutated.Never)
1333}
1334
1335func (c *Module) IsSanitizerExplicitlyDisabled(t SanitizerType) bool {
1336	return c.sanitize.isSanitizerExplicitlyDisabled(t)
1337}
1338
1339// Propagate the ubsan minimal runtime dependency when there are integer overflow sanitized static dependencies.
1340func sanitizerRuntimeDepsMutator(mctx android.TopDownMutatorContext) {
1341	// Change this to PlatformSanitizable when/if non-cc modules support ubsan sanitizers.
1342	if c, ok := mctx.Module().(*Module); ok && c.sanitize != nil {
1343		isSanitizableDependencyTag := c.SanitizableDepTagChecker()
1344		mctx.WalkDeps(func(child, parent android.Module) bool {
1345			if !isSanitizableDependencyTag(mctx.OtherModuleDependencyTag(child)) {
1346				return false
1347			}
1348
1349			d, ok := child.(*Module)
1350			if !ok || !d.static() {
1351				return false
1352			}
1353			if d.sanitize != nil {
1354				if enableMinimalRuntime(d.sanitize) {
1355					// If a static dependency is built with the minimal runtime,
1356					// make sure we include the ubsan minimal runtime.
1357					c.sanitize.Properties.MinimalRuntimeDep = true
1358				} else if enableUbsanRuntime(d.sanitize) {
1359					// If a static dependency runs with full ubsan diagnostics,
1360					// make sure we include the ubsan runtime.
1361					c.sanitize.Properties.UbsanRuntimeDep = true
1362				}
1363
1364				if c.sanitize.Properties.MinimalRuntimeDep &&
1365					c.sanitize.Properties.UbsanRuntimeDep {
1366					// both flags that this mutator might set are true, so don't bother recursing
1367					return false
1368				}
1369
1370				if c.Os() == android.Linux {
1371					c.sanitize.Properties.BuiltinsDep = true
1372				}
1373
1374				return true
1375			}
1376
1377			return false
1378		})
1379	}
1380}
1381
1382// Add the dependency to the runtime library for each of the sanitizer variants
1383func sanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) {
1384	if c, ok := mctx.Module().(*Module); ok && c.sanitize != nil {
1385		if !c.Enabled(mctx) {
1386			return
1387		}
1388		var sanitizers []string
1389		var diagSanitizers []string
1390
1391		sanProps := &c.sanitize.Properties.SanitizeMutated
1392
1393		if Bool(sanProps.All_undefined) {
1394			sanitizers = append(sanitizers, "undefined")
1395		} else {
1396			if Bool(sanProps.Undefined) {
1397				sanitizers = append(sanitizers,
1398					"bool",
1399					"integer-divide-by-zero",
1400					"return",
1401					"returns-nonnull-attribute",
1402					"shift-exponent",
1403					"unreachable",
1404					"vla-bound",
1405					// TODO(danalbert): The following checks currently have compiler performance issues.
1406					//"alignment",
1407					//"bounds",
1408					//"enum",
1409					//"float-cast-overflow",
1410					//"float-divide-by-zero",
1411					//"nonnull-attribute",
1412					//"null",
1413					//"shift-base",
1414					//"signed-integer-overflow",
1415					// TODO(danalbert): Fix UB in libc++'s __tree so we can turn this on.
1416					// https://llvm.org/PR19302
1417					// http://reviews.llvm.org/D6974
1418					// "object-size",
1419				)
1420			}
1421			sanitizers = append(sanitizers, sanProps.Misc_undefined...)
1422		}
1423
1424		if Bool(sanProps.Diag.Undefined) {
1425			diagSanitizers = append(diagSanitizers, "undefined")
1426		}
1427
1428		diagSanitizers = append(diagSanitizers, sanProps.Diag.Misc_undefined...)
1429
1430		if Bool(sanProps.Address) {
1431			sanitizers = append(sanitizers, "address")
1432			diagSanitizers = append(diagSanitizers, "address")
1433		}
1434
1435		if Bool(sanProps.Hwaddress) {
1436			sanitizers = append(sanitizers, "hwaddress")
1437		}
1438
1439		if Bool(sanProps.Thread) {
1440			sanitizers = append(sanitizers, "thread")
1441		}
1442
1443		if Bool(sanProps.Safestack) {
1444			sanitizers = append(sanitizers, "safe-stack")
1445		}
1446
1447		if Bool(sanProps.Cfi) {
1448			sanitizers = append(sanitizers, "cfi")
1449
1450			if Bool(sanProps.Diag.Cfi) {
1451				diagSanitizers = append(diagSanitizers, "cfi")
1452			}
1453		}
1454
1455		if Bool(sanProps.Integer_overflow) {
1456			sanitizers = append(sanitizers, "unsigned-integer-overflow")
1457			sanitizers = append(sanitizers, "signed-integer-overflow")
1458			if Bool(sanProps.Diag.Integer_overflow) {
1459				diagSanitizers = append(diagSanitizers, "unsigned-integer-overflow")
1460				diagSanitizers = append(diagSanitizers, "signed-integer-overflow")
1461			}
1462		}
1463
1464		if Bool(sanProps.Scudo) {
1465			sanitizers = append(sanitizers, "scudo")
1466		}
1467
1468		if Bool(sanProps.Scs) {
1469			sanitizers = append(sanitizers, "shadow-call-stack")
1470		}
1471
1472		if Bool(sanProps.Memtag_heap) && c.Binary() {
1473			sanitizers = append(sanitizers, "memtag-heap")
1474		}
1475
1476		if Bool(sanProps.Memtag_stack) {
1477			sanitizers = append(sanitizers, "memtag-stack")
1478		}
1479
1480		if Bool(sanProps.Memtag_globals) {
1481			sanitizers = append(sanitizers, "memtag-globals")
1482			// TODO(mitchp): For now, enable memtag-heap with memtag-globals because the linker
1483			// isn't new enough (https://reviews.llvm.org/differential/changeset/?ref=4243566).
1484			sanitizers = append(sanitizers, "memtag-heap")
1485		}
1486
1487		if Bool(sanProps.Fuzzer) {
1488			sanitizers = append(sanitizers, "fuzzer-no-link")
1489		}
1490
1491		// Save the list of sanitizers. These will be used again when generating
1492		// the build rules (for Cflags, etc.)
1493		c.sanitize.Properties.Sanitizers = sanitizers
1494		c.sanitize.Properties.DiagSanitizers = diagSanitizers
1495
1496		// TODO(b/150822854) Hosts have a different default behavior and assume the runtime library is used.
1497		if c.Host() {
1498			diagSanitizers = sanitizers
1499		}
1500
1501		addStaticDeps := func(dep string, hideSymbols bool) {
1502			// static executable gets static runtime libs
1503			depTag := libraryDependencyTag{Kind: staticLibraryDependency, unexportedSymbols: hideSymbols}
1504			variations := append(mctx.Target().Variations(),
1505				blueprint.Variation{Mutator: "link", Variation: "static"})
1506			if c.Device() {
1507				variations = append(variations, c.ImageVariation())
1508			}
1509			if c.UseSdk() {
1510				variations = append(variations,
1511					blueprint.Variation{Mutator: "sdk", Variation: "sdk"})
1512			}
1513			mctx.AddFarVariationDependencies(variations, depTag, dep)
1514		}
1515
1516		// Determine the runtime library required
1517		runtimeSharedLibrary := ""
1518		toolchain := c.toolchain(mctx)
1519		if Bool(sanProps.Address) {
1520			if toolchain.Musl() || (c.staticBinary() && toolchain.Bionic()) {
1521				// Use a static runtime for musl to match what clang does for glibc.
1522				addStaticDeps(config.AddressSanitizerStaticRuntimeLibrary(), false)
1523				addStaticDeps(config.AddressSanitizerCXXStaticRuntimeLibrary(), false)
1524			} else {
1525				runtimeSharedLibrary = config.AddressSanitizerRuntimeLibrary()
1526			}
1527		} else if Bool(sanProps.Hwaddress) {
1528			if c.staticBinary() {
1529				addStaticDeps(config.HWAddressSanitizerStaticLibrary(), true)
1530				addStaticDeps("libdl", false)
1531			} else {
1532				runtimeSharedLibrary = config.HWAddressSanitizerRuntimeLibrary()
1533			}
1534		} else if Bool(sanProps.Thread) {
1535			runtimeSharedLibrary = config.ThreadSanitizerRuntimeLibrary()
1536		} else if Bool(sanProps.Scudo) {
1537			if len(diagSanitizers) == 0 && !c.sanitize.Properties.UbsanRuntimeDep {
1538				runtimeSharedLibrary = config.ScudoMinimalRuntimeLibrary()
1539			} else {
1540				runtimeSharedLibrary = config.ScudoRuntimeLibrary()
1541			}
1542		} else if len(diagSanitizers) > 0 || c.sanitize.Properties.UbsanRuntimeDep ||
1543			Bool(sanProps.Fuzzer) ||
1544			Bool(sanProps.Undefined) ||
1545			Bool(sanProps.All_undefined) {
1546			if toolchain.Musl() || c.staticBinary() {
1547				// Use a static runtime for static binaries.  For sanitized glibc binaries the runtime is
1548				// added automatically by clang, but for static glibc binaries that are not sanitized but
1549				// have a sanitized dependency the runtime needs to be added manually.
1550				// Also manually add a static runtime for musl to match what clang does for glibc.
1551				// Otherwise dlopening libraries that depend on libclang_rt.ubsan_standalone.so fails with:
1552				// Error relocating ...: initial-exec TLS resolves to dynamic definition
1553				addStaticDeps(config.UndefinedBehaviorSanitizerRuntimeLibrary()+".static", true)
1554			} else {
1555				runtimeSharedLibrary = config.UndefinedBehaviorSanitizerRuntimeLibrary()
1556			}
1557		}
1558
1559		if enableMinimalRuntime(c.sanitize) || c.sanitize.Properties.MinimalRuntimeDep {
1560			addStaticDeps(config.UndefinedBehaviorSanitizerMinimalRuntimeLibrary(), true)
1561		}
1562		if c.sanitize.Properties.BuiltinsDep {
1563			addStaticDeps(config.BuiltinsRuntimeLibrary(), true)
1564		}
1565
1566		if runtimeSharedLibrary != "" && (toolchain.Bionic() || toolchain.Musl()) {
1567			// UBSan is supported on non-bionic linux host builds as well
1568
1569			// Adding dependency to the runtime library. We are using *FarVariation*
1570			// because the runtime libraries themselves are not mutated by sanitizer
1571			// mutators and thus don't have sanitizer variants whereas this module
1572			// has been already mutated.
1573			//
1574			// Note that by adding dependency with {static|shared}DepTag, the lib is
1575			// added to libFlags and LOCAL_SHARED_LIBRARIES by cc.Module
1576			if c.staticBinary() {
1577				// Most sanitizers are either disabled for static binaries or have already
1578				// handled the static binary case above through a direct call to addStaticDeps.
1579				// If not, treat the runtime shared library as a static library and hope for
1580				// the best.
1581				addStaticDeps(runtimeSharedLibrary, true)
1582			} else if !c.static() && !c.Header() {
1583				// Skip apex dependency check for sharedLibraryDependency
1584				// when sanitizer diags are enabled. Skipping the check will allow
1585				// building with diag libraries without having to list the
1586				// dependency in Apex's allowed_deps file.
1587				diagEnabled := len(diagSanitizers) > 0
1588				// dynamic executable and shared libs get shared runtime libs
1589				depTag := libraryDependencyTag{
1590					Kind:  sharedLibraryDependency,
1591					Order: earlyLibraryDependency,
1592
1593					skipApexAllowedDependenciesCheck: diagEnabled,
1594				}
1595				variations := append(mctx.Target().Variations(),
1596					blueprint.Variation{Mutator: "link", Variation: "shared"})
1597				if c.Device() {
1598					variations = append(variations, c.ImageVariation())
1599				}
1600				if c.UseSdk() {
1601					variations = append(variations,
1602						blueprint.Variation{Mutator: "sdk", Variation: "sdk"})
1603				}
1604				AddSharedLibDependenciesWithVersions(mctx, c, variations, depTag, runtimeSharedLibrary, "", true)
1605			}
1606			// static lib does not have dependency to the runtime library. The
1607			// dependency will be added to the executables or shared libs using
1608			// the static lib.
1609		}
1610	}
1611}
1612
1613type Sanitizeable interface {
1614	android.Module
1615	IsSanitizerEnabled(config android.Config, sanitizerName string) bool
1616	EnableSanitizer(sanitizerName string)
1617	AddSanitizerDependencies(ctx android.BottomUpMutatorContext, sanitizerName string)
1618}
1619
1620type JniSanitizeable interface {
1621	android.Module
1622	IsSanitizerEnabledForJni(ctx android.BaseModuleContext, sanitizerName string) bool
1623}
1624
1625func (c *Module) MinimalRuntimeDep() bool {
1626	return c.sanitize.Properties.MinimalRuntimeDep
1627}
1628
1629func (c *Module) UbsanRuntimeDep() bool {
1630	return c.sanitize.Properties.UbsanRuntimeDep
1631}
1632
1633func (c *Module) SanitizePropDefined() bool {
1634	return c.sanitize != nil
1635}
1636
1637func (c *Module) IsSanitizerEnabled(t SanitizerType) bool {
1638	return c.sanitize.isSanitizerEnabled(t)
1639}
1640
1641func (c *Module) StaticallyLinked() bool {
1642	return c.static()
1643}
1644
1645func (c *Module) SetInSanitizerDir() {
1646	if c.sanitize != nil {
1647		c.sanitize.Properties.InSanitizerDir = true
1648	}
1649}
1650
1651func (c *Module) SetSanitizer(t SanitizerType, b bool) {
1652	if c.sanitize != nil {
1653		c.sanitize.SetSanitizer(t, b)
1654	}
1655}
1656
1657var _ PlatformSanitizeable = (*Module)(nil)
1658
1659type sanitizerStaticLibsMap struct {
1660	// libsMap contains one list of modules per each image and each arch.
1661	// e.g. libs[vendor]["arm"] contains arm modules installed to vendor
1662	libsMap       map[ImageVariantType]map[string][]string
1663	libsMapLock   sync.Mutex
1664	sanitizerType SanitizerType
1665}
1666
1667func newSanitizerStaticLibsMap(t SanitizerType) *sanitizerStaticLibsMap {
1668	return &sanitizerStaticLibsMap{
1669		sanitizerType: t,
1670		libsMap:       make(map[ImageVariantType]map[string][]string),
1671	}
1672}
1673
1674// Add the current module to sanitizer static libs maps
1675// Each module should pass its exported name as names of Make and Soong can differ.
1676func (s *sanitizerStaticLibsMap) add(c LinkableInterface, name string) {
1677	image := GetImageVariantType(c)
1678	arch := c.Module().Target().Arch.ArchType.String()
1679
1680	s.libsMapLock.Lock()
1681	defer s.libsMapLock.Unlock()
1682
1683	if _, ok := s.libsMap[image]; !ok {
1684		s.libsMap[image] = make(map[string][]string)
1685	}
1686
1687	s.libsMap[image][arch] = append(s.libsMap[image][arch], name)
1688}
1689
1690// Exports makefile variables in the following format:
1691// SOONG_{sanitizer}_{image}_{arch}_STATIC_LIBRARIES
1692// e.g. SOONG_cfi_core_x86_STATIC_LIBRARIES
1693// These are to be used by use_soong_sanitized_static_libraries.
1694// See build/make/core/binary.mk for more details.
1695func (s *sanitizerStaticLibsMap) exportToMake(ctx android.MakeVarsContext) {
1696	for _, image := range android.SortedKeys(s.libsMap) {
1697		archMap := s.libsMap[ImageVariantType(image)]
1698		for _, arch := range android.SortedKeys(archMap) {
1699			libs := archMap[arch]
1700			sort.Strings(libs)
1701
1702			key := fmt.Sprintf(
1703				"SOONG_%s_%s_%s_STATIC_LIBRARIES",
1704				s.sanitizerType.variationName(),
1705				image, // already upper
1706				arch)
1707
1708			ctx.Strict(key, strings.Join(libs, " "))
1709		}
1710	}
1711}
1712
1713var cfiStaticLibsKey = android.NewOnceKey("cfiStaticLibs")
1714
1715func cfiStaticLibs(config android.Config) *sanitizerStaticLibsMap {
1716	return config.Once(cfiStaticLibsKey, func() interface{} {
1717		return newSanitizerStaticLibsMap(cfi)
1718	}).(*sanitizerStaticLibsMap)
1719}
1720
1721var hwasanStaticLibsKey = android.NewOnceKey("hwasanStaticLibs")
1722
1723func hwasanStaticLibs(config android.Config) *sanitizerStaticLibsMap {
1724	return config.Once(hwasanStaticLibsKey, func() interface{} {
1725		return newSanitizerStaticLibsMap(Hwasan)
1726	}).(*sanitizerStaticLibsMap)
1727}
1728
1729var memtagStackStaticLibsKey = android.NewOnceKey("memtagStackStaticLibs")
1730
1731func memtagStackStaticLibs(config android.Config) *sanitizerStaticLibsMap {
1732	return config.Once(memtagStackStaticLibsKey, func() interface{} {
1733		return newSanitizerStaticLibsMap(Memtag_stack)
1734	}).(*sanitizerStaticLibsMap)
1735}
1736
1737func enableMinimalRuntime(sanitize *sanitize) bool {
1738	if sanitize.isSanitizerEnabled(Asan) {
1739		return false
1740	} else if sanitize.isSanitizerEnabled(Hwasan) {
1741		return false
1742	} else if sanitize.isSanitizerEnabled(Fuzzer) {
1743		return false
1744	}
1745
1746	if enableUbsanRuntime(sanitize) {
1747		return false
1748	}
1749
1750	sanitizeProps := &sanitize.Properties.SanitizeMutated
1751	if Bool(sanitizeProps.Diag.Cfi) {
1752		return false
1753	}
1754
1755	return Bool(sanitizeProps.Integer_overflow) ||
1756		len(sanitizeProps.Misc_undefined) > 0 ||
1757		Bool(sanitizeProps.Undefined) ||
1758		Bool(sanitizeProps.All_undefined)
1759}
1760
1761func (m *Module) UbsanRuntimeNeeded() bool {
1762	return enableUbsanRuntime(m.sanitize)
1763}
1764
1765func (m *Module) MinimalRuntimeNeeded() bool {
1766	return enableMinimalRuntime(m.sanitize)
1767}
1768
1769func enableUbsanRuntime(sanitize *sanitize) bool {
1770	sanitizeProps := &sanitize.Properties.SanitizeMutated
1771	return Bool(sanitizeProps.Diag.Integer_overflow) ||
1772		Bool(sanitizeProps.Diag.Undefined) ||
1773		len(sanitizeProps.Diag.Misc_undefined) > 0
1774}
1775
1776func cfiMakeVarsProvider(ctx android.MakeVarsContext) {
1777	cfiStaticLibs(ctx.Config()).exportToMake(ctx)
1778}
1779
1780func hwasanMakeVarsProvider(ctx android.MakeVarsContext) {
1781	hwasanStaticLibs(ctx.Config()).exportToMake(ctx)
1782}
1783
1784func memtagStackMakeVarsProvider(ctx android.MakeVarsContext) {
1785	memtagStackStaticLibs(ctx.Config()).exportToMake(ctx)
1786}
1787
1788type sanitizerLibrariesTxtModule struct {
1789	android.ModuleBase
1790
1791	outputFile android.OutputPath
1792}
1793
1794var _ etc.PrebuiltEtcModule = (*sanitizerLibrariesTxtModule)(nil)
1795
1796func RegisterSanitizerLibrariesTxtType(ctx android.RegistrationContext) {
1797	ctx.RegisterModuleType("sanitizer_libraries_txt", sanitizerLibrariesTxtFactory)
1798}
1799
1800func sanitizerLibrariesTxtFactory() android.Module {
1801	m := &sanitizerLibrariesTxtModule{}
1802	android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
1803	return m
1804}
1805
1806type sanitizerLibraryDependencyTag struct {
1807	blueprint.BaseDependencyTag
1808}
1809
1810func (t sanitizerLibraryDependencyTag) AllowDisabledModuleDependency(target android.Module) bool {
1811	return true
1812}
1813
1814var _ android.AllowDisabledModuleDependency = (*sanitizerLibraryDependencyTag)(nil)
1815
1816func (txt *sanitizerLibrariesTxtModule) DepsMutator(actx android.BottomUpMutatorContext) {
1817	targets := actx.Config().Targets[android.Android]
1818	depTag := sanitizerLibraryDependencyTag{}
1819
1820	for _, target := range targets {
1821		variation := append(target.Variations(),
1822			blueprint.Variation{Mutator: "image", Variation: ""},
1823			blueprint.Variation{Mutator: "sdk", Variation: ""},
1824			blueprint.Variation{Mutator: "link", Variation: "shared"},
1825		)
1826		for _, lib := range android.SortedStringValues(sanitizerVariables) {
1827			if actx.OtherModuleFarDependencyVariantExists(variation, lib) {
1828				actx.AddFarVariationDependencies(variation, depTag, lib)
1829			}
1830
1831			prebuiltLibName := "prebuilt_" + lib
1832			if actx.OtherModuleFarDependencyVariantExists(variation, prebuiltLibName) {
1833				actx.AddFarVariationDependencies(variation, depTag, prebuiltLibName)
1834			}
1835		}
1836	}
1837
1838}
1839
1840func (txt *sanitizerLibrariesTxtModule) getSanitizerLibs(ctx android.ModuleContext) string {
1841	var sanitizerLibStems []string
1842
1843	ctx.VisitDirectDepsIf(func(m android.Module) bool {
1844		if !m.Enabled(ctx) {
1845			return false
1846		}
1847
1848		ccModule, _ := m.(*Module)
1849		if ccModule == nil || ccModule.library == nil || !ccModule.library.shared() {
1850			return false
1851		}
1852
1853		targets := ctx.Config().Targets[android.Android]
1854
1855		for _, target := range targets {
1856			if m.Target().Os == target.Os && m.Target().Arch.ArchType == target.Arch.ArchType {
1857				return true
1858			}
1859		}
1860
1861		return false
1862	}, func(m android.Module) {
1863		ccModule, _ := m.(*Module)
1864		outputFile := ccModule.outputFile
1865		if outputFile.Valid() {
1866			sanitizerLibStems = append(sanitizerLibStems, outputFile.Path().Base())
1867		}
1868	})
1869
1870	sanitizerLibStems = android.SortedUniqueStrings(sanitizerLibStems)
1871	return strings.Join(sanitizerLibStems, "\n")
1872}
1873
1874func (txt *sanitizerLibrariesTxtModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
1875	filename := txt.Name()
1876
1877	txt.outputFile = android.PathForModuleOut(ctx, filename).OutputPath
1878	android.WriteFileRule(ctx, txt.outputFile, txt.getSanitizerLibs(ctx))
1879
1880	installPath := android.PathForModuleInstall(ctx, "etc")
1881	ctx.InstallFile(installPath, filename, txt.outputFile)
1882
1883	ctx.SetOutputFiles(android.Paths{txt.outputFile}, "")
1884}
1885
1886func (txt *sanitizerLibrariesTxtModule) AndroidMkEntries() []android.AndroidMkEntries {
1887	return []android.AndroidMkEntries{{
1888		Class:      "ETC",
1889		OutputFile: android.OptionalPathForPath(txt.outputFile),
1890	}}
1891}
1892
1893// PrebuiltEtcModule interface
1894func (txt *sanitizerLibrariesTxtModule) BaseDir() string {
1895	return "etc"
1896}
1897
1898// PrebuiltEtcModule interface
1899func (txt *sanitizerLibrariesTxtModule) SubDir() string {
1900	return ""
1901}
1902
1903func (txt *sanitizerLibrariesTxtModule) OutputFiles(tag string) (android.Paths, error) {
1904	return android.Paths{txt.outputFile}, nil
1905}
1906