public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); context.RegisterCompilationStartAction( (CompilationStartAnalysisContext compilationContext) => { TaintedDataConfig taintedDataConfig = TaintedDataConfig.GetOrCreate(compilationContext.Compilation); TaintedDataSymbolMap <SourceInfo> sourceInfoSymbolMap = taintedDataConfig.GetSourceSymbolMap(this.SinkKind); if (sourceInfoSymbolMap.IsEmpty) { return; } TaintedDataSymbolMap <SinkInfo> sinkInfoSymbolMap = taintedDataConfig.GetSinkSymbolMap(this.SinkKind); if (sinkInfoSymbolMap.IsEmpty) { return; } compilationContext.RegisterOperationBlockStartAction( operationBlockStartContext => { ISymbol owningSymbol = operationBlockStartContext.OwningSymbol; if (owningSymbol.IsConfiguredToSkipAnalysis(operationBlockStartContext.Options, TaintedDataEnteringSinkDescriptor, operationBlockStartContext.Compilation, operationBlockStartContext.CancellationToken)) { return; } PooledHashSet <IOperation> rootOperationsNeedingAnalysis = PooledHashSet <IOperation> .GetInstance(); operationBlockStartContext.RegisterOperationAction( operationAnalysisContext => { IPropertyReferenceOperation propertyReferenceOperation = (IPropertyReferenceOperation)operationAnalysisContext.Operation; IOperation rootOperation = operationAnalysisContext.Operation.GetRoot(); if (sourceInfoSymbolMap.IsSourceProperty(propertyReferenceOperation.Property)) { lock (rootOperationsNeedingAnalysis) { rootOperationsNeedingAnalysis.Add(rootOperation); } } }, OperationKind.PropertyReference); operationBlockStartContext.RegisterOperationAction( operationAnalysisContext => { IInvocationOperation invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation; IOperation rootOperation = operationAnalysisContext.Operation.GetRoot(); PooledDictionary <PointsToCheck, ImmutableHashSet <string> > evaluateWithPointsToAnalysis = null; PooledDictionary <ValueContentCheck, ImmutableHashSet <string> > evaluateWithValueContentAnalysis = null; PointsToAnalysisResult pointsToAnalysisResult = null; ValueContentAnalysisResult valueContentAnalysisResult = null; if (rootOperation.TryGetEnclosingControlFlowGraph(out ControlFlowGraph cfg)) { pointsToAnalysisResult = PointsToAnalysis.TryGetOrComputeResult( cfg, owningSymbol, operationAnalysisContext.Options, WellKnownTypeProvider.GetOrCreate(operationAnalysisContext.Compilation), InterproceduralAnalysisConfiguration.Create( operationAnalysisContext.Options, SupportedDiagnostics, defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.ContextSensitive, cancellationToken: operationAnalysisContext.CancellationToken), interproceduralAnalysisPredicateOpt: null); if (pointsToAnalysisResult == null) { return; } } if (sourceInfoSymbolMap.RequiresValueContentAnalysis) { valueContentAnalysisResult = ValueContentAnalysis.TryGetOrComputeResult( cfg, owningSymbol, operationAnalysisContext.Options, WellKnownTypeProvider.GetOrCreate(operationAnalysisContext.Compilation), InterproceduralAnalysisConfiguration.Create( operationAnalysisContext.Options, SupportedDiagnostics, defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.ContextSensitive, cancellationToken: operationAnalysisContext.CancellationToken), out var copyAnalysisResult, out pointsToAnalysisResult); if (valueContentAnalysisResult == null) { return; } } try { if (sourceInfoSymbolMap.IsSourceMethod( invocationOperation.TargetMethod, invocationOperation.Arguments, invocationOperation.Arguments.Select(o => pointsToAnalysisResult[o.Kind, o.Syntax]).ToImmutableArray(), invocationOperation.Arguments.Select(o => valueContentAnalysisResult[o.Kind, o.Syntax]).ToImmutableArray(), out _)) { lock (rootOperationsNeedingAnalysis) { rootOperationsNeedingAnalysis.Add(rootOperation); } } } finally { evaluateWithPointsToAnalysis?.Free(); evaluateWithValueContentAnalysis?.Free(); } }, OperationKind.Invocation); if (taintedDataConfig.HasTaintArraySource(SinkKind)) { operationBlockStartContext.RegisterOperationAction( operationAnalysisContext => { IArrayInitializerOperation arrayInitializerOperation = (IArrayInitializerOperation)operationAnalysisContext.Operation; if (arrayInitializerOperation.GetAncestor <IArrayCreationOperation>(OperationKind.ArrayCreation)?.Type is IArrayTypeSymbol arrayTypeSymbol && sourceInfoSymbolMap.IsSourceConstantArrayOfType(arrayTypeSymbol)) { lock (rootOperationsNeedingAnalysis) { rootOperationsNeedingAnalysis.Add(operationAnalysisContext.Operation.GetRoot()); } } }, OperationKind.ArrayInitializer); } operationBlockStartContext.RegisterOperationBlockEndAction( operationBlockAnalysisContext => { try { lock (rootOperationsNeedingAnalysis) { if (!rootOperationsNeedingAnalysis.Any()) { return; } foreach (IOperation rootOperation in rootOperationsNeedingAnalysis) { if (!rootOperation.TryGetEnclosingControlFlowGraph(out var cfg)) { continue; } TaintedDataAnalysisResult taintedDataAnalysisResult = TaintedDataAnalysis.TryGetOrComputeResult( cfg, operationBlockAnalysisContext.Compilation, operationBlockAnalysisContext.OwningSymbol, operationBlockAnalysisContext.Options, TaintedDataEnteringSinkDescriptor, sourceInfoSymbolMap, taintedDataConfig.GetSanitizerSymbolMap(this.SinkKind), sinkInfoSymbolMap, operationBlockAnalysisContext.CancellationToken); if (taintedDataAnalysisResult == null) { return; } foreach (TaintedDataSourceSink sourceSink in taintedDataAnalysisResult.TaintedDataSourceSinks) { if (!sourceSink.SinkKinds.Contains(this.SinkKind)) { continue; } foreach (SymbolAccess sourceOrigin in sourceSink.SourceOrigins) { // Something like: // CA3001: Potential SQL injection vulnerability was found where '{0}' in method '{1}' may be tainted by user-controlled data from '{2}' in method '{3}'. Diagnostic diagnostic = Diagnostic.Create( this.TaintedDataEnteringSinkDescriptor, sourceSink.Sink.Location, additionalLocations: new Location[] { sourceOrigin.Location }, messageArgs: new object[] { sourceSink.Sink.Symbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat), sourceSink.Sink.AccessingMethod.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat), sourceOrigin.Symbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat), sourceOrigin.AccessingMethod.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat) }); operationBlockAnalysisContext.ReportDiagnostic(diagnostic); } } } } } finally { rootOperationsNeedingAnalysis.Free(); } }); }); }); }
public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); context.RegisterCompilationStartAction( (CompilationStartAnalysisContext compilationContext) => { TaintedDataConfig taintedDataConfig = TaintedDataConfig.GetOrCreate(compilationContext.Compilation); TaintedDataSymbolMap <SourceInfo> sourceInfoSymbolMap = taintedDataConfig.GetSourceSymbolMap(this.SinkKind); if (sourceInfoSymbolMap.IsEmpty) { return; } TaintedDataSymbolMap <SinkInfo> sinkInfoSymbolMap = taintedDataConfig.GetSinkSymbolMap(this.SinkKind); if (sinkInfoSymbolMap.IsEmpty) { return; } compilationContext.RegisterOperationBlockStartAction( operationBlockStartContext => { ISymbol owningSymbol = operationBlockStartContext.OwningSymbol; HashSet <IOperation> rootOperationsNeedingAnalysis = new HashSet <IOperation>(); operationBlockStartContext.RegisterOperationAction( operationAnalysisContext => { IPropertyReferenceOperation propertyReferenceOperation = (IPropertyReferenceOperation)operationAnalysisContext.Operation; if (sourceInfoSymbolMap.IsSourceProperty(propertyReferenceOperation.Property)) { rootOperationsNeedingAnalysis.Add(operationAnalysisContext.Operation.GetRoot()); } }, OperationKind.PropertyReference); operationBlockStartContext.RegisterOperationAction( operationAnalysisContext => { IInvocationOperation invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation; if (sourceInfoSymbolMap.IsSourceMethod(invocationOperation.TargetMethod)) { rootOperationsNeedingAnalysis.Add(operationAnalysisContext.Operation.GetRoot()); } }, OperationKind.Invocation); operationBlockStartContext.RegisterOperationBlockEndAction( operationBlockAnalysisContext => { if (!rootOperationsNeedingAnalysis.Any()) { return; } foreach (IOperation rootOperation in rootOperationsNeedingAnalysis) { TaintedDataAnalysisResult taintedDataAnalysisResult = TaintedDataAnalysis.GetOrComputeResult( rootOperation.GetEnclosingControlFlowGraph(), operationBlockAnalysisContext.Compilation, operationBlockAnalysisContext.OwningSymbol, operationBlockAnalysisContext.Options, TaintedDataEnteringSinkDescriptor, sourceInfoSymbolMap, taintedDataConfig.GetSanitizerSymbolMap(this.SinkKind), sinkInfoSymbolMap, operationBlockAnalysisContext.CancellationToken); foreach (TaintedDataSourceSink sourceSink in taintedDataAnalysisResult.TaintedDataSourceSinks) { if (!sourceSink.SinkKinds.Contains(this.SinkKind)) { continue; } foreach (SymbolAccess sourceOrigin in sourceSink.SourceOrigins) { // Something like: // CA3001: Potential SQL injection vulnerability was found where '{0}' in method '{1}' may be tainted by user-controlled data from '{2}' in method '{3}'. Diagnostic diagnostic = Diagnostic.Create( this.TaintedDataEnteringSinkDescriptor, sourceSink.Sink.Location, additionalLocations: new Location[] { sourceOrigin.Location }, messageArgs: new object[] { sourceSink.Sink.Symbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat), sourceSink.Sink.AccessingMethod.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat), sourceOrigin.Symbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat), sourceOrigin.AccessingMethod.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat) }); operationBlockAnalysisContext.ReportDiagnostic(diagnostic); } } } }); }); }); }
public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); context.RegisterCompilationStartAction( (CompilationStartAnalysisContext compilationContext) => { Compilation compilation = compilationContext.Compilation; TaintedDataConfig taintedDataConfig = TaintedDataConfig.GetOrCreate(compilation); TaintedDataSymbolMap <SourceInfo> sourceInfoSymbolMap = taintedDataConfig.GetSourceSymbolMap(this.SinkKind); if (sourceInfoSymbolMap.IsEmpty) { return; } TaintedDataSymbolMap <SinkInfo> sinkInfoSymbolMap = taintedDataConfig.GetSinkSymbolMap(this.SinkKind); if (sinkInfoSymbolMap.IsEmpty) { return; } compilationContext.RegisterOperationBlockStartAction( operationBlockStartContext => { ISymbol owningSymbol = operationBlockStartContext.OwningSymbol; AnalyzerOptions options = operationBlockStartContext.Options; CancellationToken cancellationToken = operationBlockStartContext.CancellationToken; if (owningSymbol.IsConfiguredToSkipAnalysis(options, TaintedDataEnteringSinkDescriptor, compilation, cancellationToken)) { return; } WellKnownTypeProvider wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilation); InterproceduralAnalysisConfiguration interproceduralAnalysisConfiguration = InterproceduralAnalysisConfiguration.Create( options, SupportedDiagnostics, defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.ContextSensitive, cancellationToken: cancellationToken); Lazy <ControlFlowGraph> controlFlowGraphFactory = new Lazy <ControlFlowGraph>( () => operationBlockStartContext.OperationBlocks.GetControlFlowGraph()); Lazy <PointsToAnalysisResult> pointsToFactory = new Lazy <PointsToAnalysisResult>( () => { if (controlFlowGraphFactory.Value == null) { return(null); } return(PointsToAnalysis.TryGetOrComputeResult( controlFlowGraphFactory.Value, owningSymbol, options, wellKnownTypeProvider, interproceduralAnalysisConfiguration, interproceduralAnalysisPredicateOpt: null)); }); Lazy <(PointsToAnalysisResult, ValueContentAnalysisResult)> valueContentFactory = new Lazy <(PointsToAnalysisResult, ValueContentAnalysisResult)>( () => { if (controlFlowGraphFactory.Value == null) { return(null, null); } ValueContentAnalysisResult valuecontentAnalysisResult = ValueContentAnalysis.TryGetOrComputeResult( controlFlowGraphFactory.Value, owningSymbol, options, wellKnownTypeProvider, interproceduralAnalysisConfiguration, out _, out PointsToAnalysisResult p); return(p, valuecontentAnalysisResult); }); PooledHashSet <IOperation> rootOperationsNeedingAnalysis = PooledHashSet <IOperation> .GetInstance(); operationBlockStartContext.RegisterOperationAction( operationAnalysisContext => { IPropertyReferenceOperation propertyReferenceOperation = (IPropertyReferenceOperation)operationAnalysisContext.Operation; if (sourceInfoSymbolMap.IsSourceProperty(propertyReferenceOperation.Property)) { lock (rootOperationsNeedingAnalysis) { rootOperationsNeedingAnalysis.Add(propertyReferenceOperation.GetRoot()); } } }, OperationKind.PropertyReference); operationBlockStartContext.RegisterOperationAction( operationAnalysisContext => { IInvocationOperation invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation; if (sourceInfoSymbolMap.IsSourceMethod( invocationOperation.TargetMethod, invocationOperation.Arguments, pointsToFactory, valueContentFactory, out _)) { lock (rootOperationsNeedingAnalysis) { rootOperationsNeedingAnalysis.Add(invocationOperation.GetRoot()); } } }, OperationKind.Invocation); if (taintedDataConfig.HasTaintArraySource(SinkKind)) { operationBlockStartContext.RegisterOperationAction( operationAnalysisContext => { IArrayInitializerOperation arrayInitializerOperation = (IArrayInitializerOperation)operationAnalysisContext.Operation; if (arrayInitializerOperation.GetAncestor <IArrayCreationOperation>(OperationKind.ArrayCreation)?.Type is IArrayTypeSymbol arrayTypeSymbol && sourceInfoSymbolMap.IsSourceConstantArrayOfType(arrayTypeSymbol)) { lock (rootOperationsNeedingAnalysis) { rootOperationsNeedingAnalysis.Add(operationAnalysisContext.Operation.GetRoot()); } } }, OperationKind.ArrayInitializer); } operationBlockStartContext.RegisterOperationBlockEndAction( operationBlockAnalysisContext => { try { lock (rootOperationsNeedingAnalysis) { if (!rootOperationsNeedingAnalysis.Any()) { return; } if (controlFlowGraphFactory.Value == null) { return; } foreach (IOperation rootOperation in rootOperationsNeedingAnalysis) { TaintedDataAnalysisResult taintedDataAnalysisResult = TaintedDataAnalysis.TryGetOrComputeResult( controlFlowGraphFactory.Value, operationBlockAnalysisContext.Compilation, operationBlockAnalysisContext.OwningSymbol, operationBlockAnalysisContext.Options, TaintedDataEnteringSinkDescriptor, sourceInfoSymbolMap, taintedDataConfig.GetSanitizerSymbolMap(this.SinkKind), sinkInfoSymbolMap, operationBlockAnalysisContext.CancellationToken); if (taintedDataAnalysisResult == null) { return; } foreach (TaintedDataSourceSink sourceSink in taintedDataAnalysisResult.TaintedDataSourceSinks) { if (!sourceSink.SinkKinds.Contains(this.SinkKind)) { continue; } foreach (SymbolAccess sourceOrigin in sourceSink.SourceOrigins) { // Something like: // CA3001: Potential SQL injection vulnerability was found where '{0}' in method '{1}' may be tainted by user-controlled data from '{2}' in method '{3}'. Diagnostic diagnostic = Diagnostic.Create( this.TaintedDataEnteringSinkDescriptor, sourceSink.Sink.Location, additionalLocations: new Location[] { sourceOrigin.Location }, messageArgs: new object[] { sourceSink.Sink.Symbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat), sourceSink.Sink.AccessingMethod.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat), sourceOrigin.Symbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat), sourceOrigin.AccessingMethod.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat) }); operationBlockAnalysisContext.ReportDiagnostic(diagnostic); } } } } } finally { rootOperationsNeedingAnalysis.Free(); } }); }); }); }