public bool HasTaintArraySource(SinkKind sinkKind, Configuration config) { return(GetSourceInfos(sinkKind, config).Any(o => o.TaintConstantArray)); }
public TaintConfiguration(WellKnownTypeProvider wellKnownTypeProvider, Configuration config) { WellKnownTypeProvider = wellKnownTypeProvider; using PooledDictionary <SinkKind, Lazy <TaintedDataSymbolMap <SourceInfo> > > sourceSymbolMapBuilder = PooledDictionary <SinkKind, Lazy <TaintedDataSymbolMap <SourceInfo> > > .GetInstance(); using PooledDictionary <SinkKind, Lazy <TaintedDataSymbolMap <SanitizerInfo> > > sanitizerSymbolMapBuilder = PooledDictionary <SinkKind, Lazy <TaintedDataSymbolMap <SanitizerInfo> > > .GetInstance(); using PooledDictionary <SinkKind, Lazy <TaintedDataSymbolMap <SinkInfo> > > sinkSymbolMapBuilder = PooledDictionary <SinkKind, Lazy <TaintedDataSymbolMap <SinkInfo> > > .GetInstance(); // For tainted data rules with the same set of sources, we'll reuse the same TaintedDataSymbolMap<SourceInfo> instance. // Same for sanitizers. using PooledDictionary <ImmutableHashSet <SourceInfo>, Lazy <TaintedDataSymbolMap <SourceInfo> > > sourcesToSymbolMap = PooledDictionary <ImmutableHashSet <SourceInfo>, Lazy <TaintedDataSymbolMap <SourceInfo> > > .GetInstance(); using PooledDictionary <ImmutableHashSet <SanitizerInfo>, Lazy <TaintedDataSymbolMap <SanitizerInfo> > > sanitizersToSymbolMap = PooledDictionary <ImmutableHashSet <SanitizerInfo>, Lazy <TaintedDataSymbolMap <SanitizerInfo> > > .GetInstance(); // Build a mapping of (sourceSet, sanitizerSet) -> (sinkKinds, sinkSet), so we'll reuse the same TaintedDataSymbolMap<SinkInfo> instance. using PooledDictionary <(ImmutableHashSet <SourceInfo> SourceInfos, ImmutableHashSet <SanitizerInfo> SanitizerInfos), (ImmutableHashSet <SinkKind> .Builder SinkKinds, ImmutableHashSet <SinkInfo> .Builder SinkInfos)> sourceSanitizersToSinks = PooledDictionary <(ImmutableHashSet <SourceInfo> SourceInfos, ImmutableHashSet <SanitizerInfo> SanitizerInfos), (ImmutableHashSet <SinkKind> .Builder SinkKinds, ImmutableHashSet <SinkInfo> .Builder SinkInfos)> .GetInstance(); // Using LazyThreadSafetyMode.ExecutionAndPublication to avoid instantiating multiple times. foreach (SinkKind sinkKind in Enum.GetValues(typeof(TaintType)).Cast <SinkKind>().Except(ConstAnalyzer.ConstantTaintTypes.Cast <SinkKind>())) { ImmutableHashSet <SourceInfo> sources = GetSourceInfos(sinkKind, config); if (!sourcesToSymbolMap.TryGetValue(sources, out Lazy <TaintedDataSymbolMap <SourceInfo> > lazySourceSymbolMap)) { lazySourceSymbolMap = new Lazy <TaintedDataSymbolMap <SourceInfo> >( () => { return(new TaintedDataSymbolMap <SourceInfo>(WellKnownTypeProvider, sources)); }, LazyThreadSafetyMode.ExecutionAndPublication); sourcesToSymbolMap.Add(sources, lazySourceSymbolMap); } sourceSymbolMapBuilder.Add(sinkKind, lazySourceSymbolMap); ImmutableHashSet <SanitizerInfo> sanitizers = GetSanitizerInfos(sinkKind, config); if (!sanitizersToSymbolMap.TryGetValue(sanitizers, out Lazy <TaintedDataSymbolMap <SanitizerInfo> > lazySanitizerSymbolMap)) { lazySanitizerSymbolMap = new Lazy <TaintedDataSymbolMap <SanitizerInfo> >( () => { return(new TaintedDataSymbolMap <SanitizerInfo>(WellKnownTypeProvider, sanitizers)); }, LazyThreadSafetyMode.ExecutionAndPublication); sanitizersToSymbolMap.Add(sanitizers, lazySanitizerSymbolMap); } sanitizerSymbolMapBuilder.Add(sinkKind, lazySanitizerSymbolMap); ImmutableHashSet <SinkInfo> sinks = GetSinkInfos(sinkKind, config); if (!sourceSanitizersToSinks.TryGetValue((sources, sanitizers), out (ImmutableHashSet <SinkKind> .Builder SinkKinds, ImmutableHashSet <SinkInfo> .Builder SinkInfos)sinksPair)) { sinksPair = (ImmutableHashSet.CreateBuilder <SinkKind>(), ImmutableHashSet.CreateBuilder <SinkInfo>()); sourceSanitizersToSinks.Add((sources, sanitizers), sinksPair); } sinksPair.SinkKinds.Add(sinkKind); sinksPair.SinkInfos.UnionWith(sinks); } foreach (KeyValuePair <(ImmutableHashSet <SourceInfo> SourceInfos, ImmutableHashSet <SanitizerInfo> SanitizerInfos), (ImmutableHashSet <SinkKind> .Builder SinkKinds, ImmutableHashSet <SinkInfo> .Builder SinkInfos)> kvp in sourceSanitizersToSinks) { ImmutableHashSet <SinkInfo> sinks = kvp.Value.SinkInfos.ToImmutable(); Lazy <TaintedDataSymbolMap <SinkInfo> > lazySinkSymbolMap = new Lazy <TaintedDataSymbolMap <SinkInfo> >( () => { return(new TaintedDataSymbolMap <SinkInfo>(WellKnownTypeProvider, sinks)); }, LazyThreadSafetyMode.ExecutionAndPublication); foreach (SinkKind sinkKind in kvp.Value.SinkKinds) { sinkSymbolMapBuilder.Add(sinkKind, lazySinkSymbolMap); } } foreach (SinkKind sinkKind in ConstAnalyzer.ConstantTaintTypes) { ImmutableHashSet <SinkInfo> sinks = GetSinkInfos(sinkKind, config); Lazy <TaintedDataSymbolMap <SinkInfo> > lazySinkSymbolMap = new Lazy <TaintedDataSymbolMap <SinkInfo> >( () => { return(new TaintedDataSymbolMap <SinkInfo>(WellKnownTypeProvider, sinks)); }, LazyThreadSafetyMode.ExecutionAndPublication); sinkSymbolMapBuilder.Add(sinkKind, lazySinkSymbolMap); } SourceSymbolMap = sourceSymbolMapBuilder.ToImmutableDictionary(); SanitizerSymbolMap = sanitizerSymbolMapBuilder.ToImmutableDictionary(); SinkSymbolMap = sinkSymbolMapBuilder.ToImmutableDictionary(); }
private ImmutableHashSet <SourceInfo> GetSourceInfos(SinkKind sinkKind, Configuration config) { var typeToInfos = new Dictionary <string, AggregatedSource>(); foreach (var entryPoint in config.TaintEntryPoints) { if (!typeToInfos.TryGetValue(entryPoint.Key, out var value)) { value = new AggregatedSource(); typeToInfos.Add(entryPoint.Key, value); } if (value.entryPoint != null) { throw new ArgumentException($"Duplicate entrypoint for type '{entryPoint.Key}'"); } value.entryPoint = entryPoint.Value; } foreach (var source in config.TaintSources) { if (source.TaintTypes != null && !source.TaintTypes.Contains((TaintType)sinkKind)) { continue; } if (!typeToInfos.TryGetValue(source.Type, out var value)) { value = new AggregatedSource(); typeToInfos.Add(source.Type, value); } if (value.source != null) { throw new ArgumentException($"Duplicate taint source for type '{source.Type}'"); } value.source = source; } foreach (var sanitizer in config.Sanitizers) { var methods = sanitizer.Methods.Where(x => x.InOut != null && x.InOut.Any(io => io.outArgumentName != TaintedTargetValue.Return)); if (!methods.Any()) { continue; } if (!typeToInfos.TryGetValue(sanitizer.Type, out var value)) { value = new AggregatedSource(); typeToInfos.Add(sanitizer.Type, value); } if (value.sanitizer != null) { throw new ArgumentException($"Duplicate sanitizer for type '{sanitizer.Type}'"); } value.sanitizer = sanitizer; } foreach (var transfer in config.Transfers) { if (!typeToInfos.TryGetValue(transfer.Type, out var value)) { value = new AggregatedSource(); typeToInfos.Add(transfer.Type, value); } if (value.transfer != null) { throw new ArgumentException($"Duplicate taint source for type '{transfer.Type}'"); } value.transfer = transfer; } var sourceInfosBuilder = PooledHashSet <SourceInfo> .GetInstance(); foreach (var type in typeToInfos) { bool?isIterface = null; if (type.Value.sanitizer?.IsInterface != null) { if (isIterface.HasValue && isIterface != type.Value.sanitizer.IsInterface) { throw new ArgumentException($"Inconsistent 'IsInterface' for type '{type.Key}'"); } else { isIterface = type.Value.sanitizer.IsInterface; } } if (type.Value.source?.IsInterface != null) { if (isIterface.HasValue && isIterface != type.Value.sanitizer.IsInterface) { throw new ArgumentException($"Inconsistent 'IsInterface' for type '{type.Key}'"); } else { isIterface = type.Value.source.IsInterface; } } if (type.Value.transfer?.IsInterface != null) { if (isIterface.HasValue && isIterface != type.Value.transfer.IsInterface) { throw new ArgumentException($"Inconsistent 'IsInterface' for type '{type.Key}'"); } else { isIterface = type.Value.sanitizer.IsInterface; } } SourceInfo metadata; if (type.Value.source != null && type.Value.source.Methods == null && type.Value.source.Properties == null) { metadata = new SourceInfo( type.Key, isInterface: isIterface ?? false, taintedMethods: ImmutableHashSet <(MethodMatcher, ImmutableHashSet <string>)> .Empty, taintedMethodsNeedsPointsToAnalysis: ImmutableHashSet <(MethodMatcher, ImmutableHashSet <(PointsToCheck, string)>)> .Empty, taintedMethodsNeedsValueContentAnalysis: ImmutableHashSet <(MethodMatcher, ImmutableHashSet <(ValueContentCheck, string)>)> .Empty, transferMethods: ImmutableHashSet <(MethodMatcher, ImmutableHashSet <(string, string)>)> .Empty, allProperitesAreTainted: true, allFieldsAreTainted: true ); } else { metadata = new SourceInfo( type.Key, isInterface: isIterface ?? false, taintedProperties: type.Value.source?.Properties?.ToImmutableHashSet(StringComparer.Ordinal) ?? ImmutableHashSet <string> .Empty, dependencyFullTypeNames: type.Value.entryPoint?.Dependency?.ToImmutableArray(), taintedArguments: type.Value.entryPoint != null ? new ParameterMatcher[] { (parameter, wellKnownTypeProvider) => { if (!(parameter.ContainingSymbol is IMethodSymbol methodSymbol) || methodSymbol.IsPropertyAccessor()) { return(false); } if (type.Value.entryPoint.Class != null) { if (!(methodSymbol.ContainingSymbol is INamedTypeSymbol typeSymbol)) { return(false); } var classCache = s_classIsControllerByCompilation.GetOrCreateValue(wellKnownTypeProvider.Compilation, (compilation) => new ConcurrentDictionary <INamedTypeSymbol, bool>()); if (!classCache.TryGetValue(typeSymbol, out bool isTaintEntryClass)) { isTaintEntryClass = false; bool IsTaintEntryClassBySuffix() { if (typeSymbol.Name.EndsWith(type.Value.entryPoint.Class.Suffix.Text, StringComparison.Ordinal)) { return(true); } else if (type.Value.entryPoint.Class.Suffix.IncludeParent && typeSymbol.GetBaseTypes().Any(x => x.Name.EndsWith(type.Value.entryPoint.Class.Suffix.Text, StringComparison.Ordinal))) { return(true); } else { return(false); } } if (type.Value.entryPoint.Class.Accessibility != null && type.Value.entryPoint.Class.Accessibility.All(a => a != typeSymbol.DeclaredAccessibility)) { isTaintEntryClass = false; } else { if (type.Value.entryPoint.Class.Suffix != null && type.Value.entryPoint.Class.Parent == null) { isTaintEntryClass = IsTaintEntryClassBySuffix(); } else if (type.Value.entryPoint.Class.Parent != null) { var parentType = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(type.Value.entryPoint.Class.Parent); if ((parentType.TypeKind == TypeKind.Interface && typeSymbol.AllInterfaces.Any(x => x == parentType)) || typeSymbol.GetBaseTypesAndThis().Any(x => x == parentType)) { isTaintEntryClass = type.Value.entryPoint.Class.Suffix != null ? IsTaintEntryClassBySuffix() : true; } } if (type.Value.entryPoint.Class.Attributes?.Exclude != null && type.Value.entryPoint.Class.Attributes.Exclude.Any(x => typeSymbol.HasDerivedTypeAttribute(wellKnownTypeProvider.GetOrCreateTypeByMetadataName(x.Type)))) { isTaintEntryClass = false; } else if (type.Value.entryPoint.Class.Attributes?.Include != null && type.Value.entryPoint.Class.Attributes.Include.Any(x => typeSymbol.HasDerivedTypeAttribute(wellKnownTypeProvider.GetOrCreateTypeByMetadataName(x.Type)))) { isTaintEntryClass = true; } } classCache.TryAdd(typeSymbol, isTaintEntryClass); } if (!isTaintEntryClass) { return(false); } } if (type.Value.entryPoint.Method != null) { if (type.Value.entryPoint.Method.Static.HasValue && type.Value.entryPoint.Method.Static != methodSymbol.IsStatic) { return(false); } if (type.Value.entryPoint.Method.Name != null) { if (type.Value.entryPoint.Method.NameRegex == null) { return(type.Value.entryPoint.Method.Name == methodSymbol.Name); } if (!type.Value.entryPoint.Method.NameRegex.IsMatch(methodSymbol.Name)) { return(false); } } if (type.Value.entryPoint.Method.IncludeConstructor.HasValue && type.Value.entryPoint.Method.IncludeConstructor != methodSymbol.IsConstructor()) { return(false); } if (type.Value.entryPoint.Method.Accessibility.All(a => a != methodSymbol.DeclaredAccessibility)) { return(false); } if (type.Value.entryPoint.Method.Attributes?.Exclude != null && type.Value.entryPoint.Method.Attributes.Exclude.Any(x => methodSymbol.HasDerivedMethodAttribute(wellKnownTypeProvider.GetOrCreateTypeByMetadataName(x.Type)))) { return(false); } } if (type.Value.entryPoint.Parameter?.Attributes?.Exclude != null && type.Value.entryPoint.Parameter.Attributes.Exclude.Any(x => parameter.HasAttribute(wellKnownTypeProvider.GetOrCreateTypeByMetadataName(x.Type)))) { return(false); } return(true); } }.ToImmutableHashSet() : ImmutableHashSet <ParameterMatcher> .Empty,