1// Copyright 2020 The Android Open Source Project 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 rust 16 17import ( 18 "android/soong/android" 19 "android/soong/cc" 20 "android/soong/rust/config" 21 "fmt" 22 "github.com/google/blueprint" 23) 24 25type SanitizeProperties struct { 26 // enable AddressSanitizer, HWAddressSanitizer, and others. 27 Sanitize struct { 28 Address *bool `android:"arch_variant"` 29 Hwaddress *bool `android:"arch_variant"` 30 Fuzzer *bool `android:"arch_variant"` 31 Never *bool `android:"arch_variant"` 32 } 33 SanitizerEnabled bool `blueprint:"mutated"` 34 SanitizeDep bool `blueprint:"mutated"` 35 36 // Used when we need to place libraries in their own directory, such as ASAN. 37 InSanitizerDir bool `blueprint:"mutated"` 38} 39 40var fuzzerFlags = []string{ 41 "-C passes='sancov'", 42 43 "--cfg fuzzing", 44 "-C llvm-args=-sanitizer-coverage-level=3", 45 "-C llvm-args=-sanitizer-coverage-trace-compares", 46 "-C llvm-args=-sanitizer-coverage-inline-8bit-counters", 47 "-C llvm-args=-sanitizer-coverage-trace-geps", 48 "-C llvm-args=-sanitizer-coverage-prune-blocks=0", 49 50 // Sancov breaks with lto 51 // TODO: Remove when https://bugs.llvm.org/show_bug.cgi?id=41734 is resolved and sancov works with LTO 52 "-C lto=no", 53} 54 55var asanFlags = []string{ 56 "-Z sanitizer=address", 57} 58 59var hwasanFlags = []string{ 60 "-Z sanitizer=hwaddress", 61 "-C target-feature=+tagged-globals", 62} 63 64func boolPtr(v bool) *bool { 65 if v { 66 return &v 67 } else { 68 return nil 69 } 70} 71 72func init() { 73} 74func (sanitize *sanitize) props() []interface{} { 75 return []interface{}{&sanitize.Properties} 76} 77 78func (sanitize *sanitize) begin(ctx BaseModuleContext) { 79 s := sanitize.Properties.Sanitize 80 81 // TODO:(b/178369775) 82 // For now sanitizing is only supported on devices 83 if ctx.Os() == android.Android && Bool(s.Fuzzer) { 84 sanitize.Properties.SanitizerEnabled = true 85 } 86 87 if ctx.Os() == android.Android && Bool(s.Address) { 88 sanitize.Properties.SanitizerEnabled = true 89 } 90 91 // HWASan requires AArch64 hardware feature (top-byte-ignore). 92 if ctx.Arch().ArchType != android.Arm64 { 93 s.Hwaddress = nil 94 } 95 96 if ctx.Os() == android.Android && Bool(s.Hwaddress) { 97 sanitize.Properties.SanitizerEnabled = true 98 } 99} 100 101type sanitize struct { 102 Properties SanitizeProperties 103} 104 105func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags, PathDeps) { 106 if !sanitize.Properties.SanitizerEnabled { 107 return flags, deps 108 } 109 if Bool(sanitize.Properties.Sanitize.Fuzzer) { 110 flags.RustFlags = append(flags.RustFlags, fuzzerFlags...) 111 if ctx.Arch().ArchType == android.Arm64 { 112 flags.RustFlags = append(flags.RustFlags, hwasanFlags...) 113 } else { 114 flags.RustFlags = append(flags.RustFlags, asanFlags...) 115 } 116 } 117 if Bool(sanitize.Properties.Sanitize.Address) { 118 flags.RustFlags = append(flags.RustFlags, asanFlags...) 119 } 120 if Bool(sanitize.Properties.Sanitize.Hwaddress) { 121 flags.RustFlags = append(flags.RustFlags, hwasanFlags...) 122 } 123 return flags, deps 124} 125 126func (sanitize *sanitize) deps(ctx BaseModuleContext, deps Deps) Deps { 127 return deps 128} 129 130func rustSanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) { 131 if mod, ok := mctx.Module().(*Module); ok && mod.sanitize != nil { 132 if !mod.Enabled() { 133 return 134 } 135 136 variations := mctx.Target().Variations() 137 var depTag blueprint.DependencyTag 138 var deps []string 139 140 if mod.IsSanitizerEnabled(cc.Asan) || 141 (mod.IsSanitizerEnabled(cc.Fuzzer) && mctx.Arch().ArchType != android.Arm64) { 142 variations = append(variations, 143 blueprint.Variation{Mutator: "link", Variation: "shared"}) 144 depTag = cc.SharedDepTag() 145 deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "asan")} 146 } else if mod.IsSanitizerEnabled(cc.Hwasan) || 147 (mod.IsSanitizerEnabled(cc.Fuzzer) && mctx.Arch().ArchType == android.Arm64) { 148 // TODO(b/180495975): HWASan for static Rust binaries isn't supported yet. 149 if binary, ok := mod.compiler.(*binaryDecorator); ok { 150 if Bool(binary.Properties.Static_executable) { 151 mctx.ModuleErrorf("HWASan is not supported for static Rust executables yet.") 152 } 153 } 154 155 if mod.StaticallyLinked() { 156 variations = append(variations, 157 blueprint.Variation{Mutator: "link", Variation: "static"}) 158 depTag = cc.StaticDepTag(false) 159 deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "hwasan_static")} 160 } else { 161 variations = append(variations, 162 blueprint.Variation{Mutator: "link", Variation: "shared"}) 163 depTag = cc.SharedDepTag() 164 deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "hwasan")} 165 } 166 } 167 168 mctx.AddFarVariationDependencies(variations, depTag, deps...) 169 } 170} 171 172func (sanitize *sanitize) SetSanitizer(t cc.SanitizerType, b bool) { 173 sanitizerSet := false 174 switch t { 175 case cc.Fuzzer: 176 sanitize.Properties.Sanitize.Fuzzer = boolPtr(b) 177 sanitizerSet = true 178 case cc.Asan: 179 sanitize.Properties.Sanitize.Address = boolPtr(b) 180 sanitizerSet = true 181 case cc.Hwasan: 182 sanitize.Properties.Sanitize.Hwaddress = boolPtr(b) 183 sanitizerSet = true 184 default: 185 panic(fmt.Errorf("setting unsupported sanitizerType %d", t)) 186 } 187 if b && sanitizerSet { 188 sanitize.Properties.SanitizerEnabled = true 189 } 190} 191 192func (m *Module) UbsanRuntimeNeeded() bool { 193 return false 194} 195 196func (m *Module) MinimalRuntimeNeeded() bool { 197 return false 198} 199 200func (m *Module) UbsanRuntimeDep() bool { 201 return false 202} 203 204func (m *Module) MinimalRuntimeDep() bool { 205 return false 206} 207 208// Check if the sanitizer is explicitly disabled (as opposed to nil by 209// virtue of not being set). 210func (sanitize *sanitize) isSanitizerExplicitlyDisabled(t cc.SanitizerType) bool { 211 if sanitize == nil { 212 return false 213 } 214 if Bool(sanitize.Properties.Sanitize.Never) { 215 return true 216 } 217 sanitizerVal := sanitize.getSanitizerBoolPtr(t) 218 return sanitizerVal != nil && *sanitizerVal == false 219} 220 221// There isn't an analog of the method above (ie:isSanitizerExplicitlyEnabled) 222// because enabling a sanitizer either directly (via the blueprint) or 223// indirectly (via a mutator) sets the bool ptr to true, and you can't 224// distinguish between the cases. It isn't needed though - both cases can be 225// treated identically. 226func (sanitize *sanitize) isSanitizerEnabled(t cc.SanitizerType) bool { 227 if sanitize == nil || !sanitize.Properties.SanitizerEnabled { 228 return false 229 } 230 231 sanitizerVal := sanitize.getSanitizerBoolPtr(t) 232 return sanitizerVal != nil && *sanitizerVal == true 233} 234 235func (sanitize *sanitize) getSanitizerBoolPtr(t cc.SanitizerType) *bool { 236 switch t { 237 case cc.Fuzzer: 238 return sanitize.Properties.Sanitize.Fuzzer 239 case cc.Asan: 240 return sanitize.Properties.Sanitize.Address 241 case cc.Hwasan: 242 return sanitize.Properties.Sanitize.Hwaddress 243 default: 244 return nil 245 } 246} 247 248func (sanitize *sanitize) AndroidMk(ctx AndroidMkContext, entries *android.AndroidMkEntries) { 249 // Add a suffix for hwasan rlib libraries to allow surfacing both the sanitized and 250 // non-sanitized variants to make without a name conflict. 251 if entries.Class == "RLIB_LIBRARIES" || entries.Class == "STATIC_LIBRARIES" { 252 if sanitize.isSanitizerEnabled(cc.Hwasan) { 253 entries.SubName += ".hwasan" 254 } 255 } 256} 257 258func (mod *Module) SanitizerSupported(t cc.SanitizerType) bool { 259 if mod.Host() { 260 return false 261 } 262 switch t { 263 case cc.Fuzzer: 264 return true 265 case cc.Asan: 266 return true 267 case cc.Hwasan: 268 return true 269 default: 270 return false 271 } 272} 273 274func (mod *Module) IsSanitizerEnabled(t cc.SanitizerType) bool { 275 return mod.sanitize.isSanitizerEnabled(t) 276} 277 278func (mod *Module) IsSanitizerExplicitlyDisabled(t cc.SanitizerType) bool { 279 if mod.Host() { 280 return true 281 } 282 283 // TODO(b/178365482): Rust/CC interop doesn't work just yet; don't sanitize rust_ffi modules until 284 // linkage issues are resolved. 285 if lib, ok := mod.compiler.(libraryInterface); ok { 286 if lib.shared() || lib.static() { 287 return true 288 } 289 } 290 291 return mod.sanitize.isSanitizerExplicitlyDisabled(t) 292} 293 294func (mod *Module) SanitizeDep() bool { 295 return mod.sanitize.Properties.SanitizeDep 296} 297 298func (mod *Module) SetSanitizer(t cc.SanitizerType, b bool) { 299 if !Bool(mod.sanitize.Properties.Sanitize.Never) { 300 mod.sanitize.SetSanitizer(t, b) 301 } 302} 303 304func (mod *Module) SetSanitizeDep(b bool) { 305 mod.sanitize.Properties.SanitizeDep = b 306} 307 308func (mod *Module) StaticallyLinked() bool { 309 if lib, ok := mod.compiler.(libraryInterface); ok { 310 return lib.rlib() || lib.static() 311 } else if binary, ok := mod.compiler.(*binaryDecorator); ok { 312 return Bool(binary.Properties.Static_executable) 313 } 314 return false 315} 316 317func (mod *Module) SetInSanitizerDir() { 318 mod.sanitize.Properties.InSanitizerDir = true 319} 320 321func (mod *Module) SanitizeNever() bool { 322 return Bool(mod.sanitize.Properties.Sanitize.Never) 323} 324 325var _ cc.PlatformSanitizeable = (*Module)(nil) 326 327func IsSanitizableDependencyTag(tag blueprint.DependencyTag) bool { 328 switch t := tag.(type) { 329 case dependencyTag: 330 return t.library 331 default: 332 return cc.IsSanitizableDependencyTag(tag) 333 } 334} 335 336func (m *Module) SanitizableDepTagChecker() cc.SantizableDependencyTagChecker { 337 return IsSanitizableDependencyTag 338} 339