Example #1
0
        private static bool ReportDiagnosticIfNecessary(OperationAnalysisContext operationContext,
                                                        IOperation argumentValue,
                                                        SyntaxNode syntax,
                                                        ISymbol invokedSymbol,
                                                        ISymbol containingMethod)
        {
            if (argumentValue.Type.SpecialType != SpecialType.System_String || !argumentValue.ConstantValue.HasValue)
            {
                // We have a candidate for diagnostic. perform more precise dataflow analysis.
                var cfg = argumentValue.GetEnclosingControlFlowGraph();
                var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(operationContext.Compilation);
                var valueContentResult    = ValueContentAnalysis.TryGetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider,
                                                                                       operationContext.Options, Rule, operationContext.CancellationToken);
                if (valueContentResult != null)
                {
                    ValueContentAbstractValue value = valueContentResult[argumentValue.Kind, argumentValue.Syntax];
                    if (value.NonLiteralState == ValueContainsNonLiteralState.No)
                    {
                        // The value is a constant literal or default/unitialized, so avoid flagging this usage.
                        return(false);
                    }
                }

                // Review if the symbol passed to {invocation} in {method/field/constructor/etc} has user input.
                operationContext.ReportDiagnostic(syntax.CreateDiagnostic(Rule,
                                                                          invokedSymbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat),
                                                                          containingMethod.Name));
                return(true);
            }

            return(false);
        }
Example #2
0
        internal static IEnumerable <object> TryAnalyze(
            SyntaxNode methodNode,
            SemanticModel semanticModel,
            CSharpCompilation compilation)
        {
            var cfg = ControlFlowGraph.Create(methodNode, semanticModel);
            var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilation);
            var owningSymbol          = semanticModel.GetDeclaredSymbol(methodNode);

            var valueContentAnalysis = ValueContentAnalysis.TryGetOrComputeResult(cfg,
                                                                                  owningSymbol,
                                                                                  wellKnownTypeProvider,
                                                                                  new AnalyzerOptions(ImmutableArray <AdditionalText> .Empty),
                                                                                  null,
                                                                                  CancellationToken.None
                                                                                  );

            if (HasLiteralStateLoss(valueContentAnalysis))
            {
                return(null);
            }

            var returnValues = valueContentAnalysis.ReturnValueAndPredicateKindOpt?.Value.LiteralValues;

            return(returnValues);
        }
Example #3
0
                DataFlowAnalysisResult <ValueContentBlockAnalysisResult, ValueContentAbstractValue>?ComputeValueContentAnalysisResult()
                {
                    var cfg = operationBlockStartContext.OperationBlocks.GetControlFlowGraph();
                    if (cfg != null)
                    {
                        var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(operationBlockStartContext.Compilation);
                        return(ValueContentAnalysis.TryGetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider,
                                                                          operationBlockStartContext.Options, Rule, PointsToAnalysisKind.PartialWithoutTrackingFieldsAndProperties, operationBlockStartContext.CancellationToken));
                    }

                    return(null);
                }
Example #4
0
        public override void Initialize(AnalysisContext context)
        {
            context.EnableConcurrentExecution();
            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);

            context.RegisterCompilationStartAction(compilationContext =>
            {
                INamedTypeSymbol localizableStateAttributeSymbol  = WellKnownTypes.LocalizableAttribute(compilationContext.Compilation);
                INamedTypeSymbol conditionalAttributeSymbol       = WellKnownTypes.ConditionalAttribute(compilationContext.Compilation);
                INamedTypeSymbol systemConsoleSymbol              = WellKnownTypes.Console(compilationContext.Compilation);
                ImmutableHashSet <INamedTypeSymbol> typesToIgnore = GetTypesToIgnore(compilationContext.Compilation);

                compilationContext.RegisterOperationBlockStartAction(operationBlockStartContext =>
                {
                    if (!(operationBlockStartContext.OwningSymbol is IMethodSymbol containingMethod))
                    {
                        return;
                    }

                    var lazyValueContentResult = new Lazy <DataFlowAnalysisResult <ValueContentBlockAnalysisResult, ValueContentAbstractValue> >(
                        valueFactory: ComputeValueContentAnalysisResult, isThreadSafe: false);

                    operationBlockStartContext.RegisterOperationAction(operationContext =>
                    {
                        var argument = (IArgumentOperation)operationContext.Operation;
                        IMethodSymbol targetMethod = null;
                        switch (argument.Parent)
                        {
                        case IInvocationOperation invocation:
                            targetMethod = invocation.TargetMethod;
                            break;

                        case IObjectCreationOperation objectCreation:
                            targetMethod = objectCreation.Constructor;
                            break;
                        }

                        if (ShouldAnalyze(targetMethod))
                        {
                            AnalyzeArgument(argument.Parameter, containingPropertySymbolOpt: null, operation: argument, reportDiagnostic: operationContext.ReportDiagnostic);
                        }
                    }, OperationKind.Argument);

                    operationBlockStartContext.RegisterOperationAction(operationContext =>
                    {
                        var propertyReference = (IPropertyReferenceOperation)operationContext.Operation;
                        if (propertyReference.Parent is IAssignmentOperation assignment &&
                            assignment.Target == propertyReference &&
                            !propertyReference.Property.IsIndexer &&
                            propertyReference.Property.SetMethod?.Parameters.Length == 1 &&
                            ShouldAnalyze(propertyReference.Property))
                        {
                            IParameterSymbol valueSetterParam = propertyReference.Property.SetMethod.Parameters[0];
                            AnalyzeArgument(valueSetterParam, propertyReference.Property, assignment, operationContext.ReportDiagnostic);
                        }
                    }, OperationKind.PropertyReference);

                    return;

                    // Local functions
                    bool ShouldAnalyze(ISymbol symbol)
                    => symbol != null && !symbol.IsConfiguredToSkipAnalysis(operationBlockStartContext.Options, Rule, operationBlockStartContext.Compilation, operationBlockStartContext.CancellationToken);

                    void AnalyzeArgument(IParameterSymbol parameter, IPropertySymbol containingPropertySymbolOpt, IOperation operation, Action <Diagnostic> reportDiagnostic)
                    {
                        if (ShouldBeLocalized(parameter.OriginalDefinition, containingPropertySymbolOpt?.OriginalDefinition, localizableStateAttributeSymbol, conditionalAttributeSymbol, systemConsoleSymbol, typesToIgnore) &&
                            lazyValueContentResult.Value != null)
                        {
                            ValueContentAbstractValue stringContentValue = lazyValueContentResult.Value[operation.Kind, operation.Syntax];
                            if (stringContentValue.IsLiteralState)
                            {
                                Debug.Assert(stringContentValue.LiteralValues.Count > 0);

                                if (stringContentValue.LiteralValues.Any(l => !(l is string)))
                                {
                                    return;
                                }

                                var stringLiteralValues = stringContentValue.LiteralValues.Select(l => (string)l);

                                // FxCop compat: Do not fire if the literal value came from a default parameter value
                                if (stringContentValue.LiteralValues.Count == 1 &&
                                    parameter.IsOptional &&
                                    parameter.ExplicitDefaultValue is string defaultValue &&
                                    defaultValue == stringLiteralValues.Single())
                                {
                                    return;
                                }

                                // FxCop compat: Do not fire if none of the string literals have any non-control character.
                                if (!LiteralValuesHaveNonControlCharacters(stringLiteralValues))
                                {
                                    return;
                                }

                                // FxCop compat: Filter out xml string literals.
                                var filteredStrings = stringLiteralValues.Where(literal => !LooksLikeXmlTag(literal));
                                if (filteredStrings.Any())
                                {
                                    // Method '{0}' passes a literal string as parameter '{1}' of a call to '{2}'. Retrieve the following string(s) from a resource table instead: "{3}".
                                    var arg1       = containingMethod.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat);
                                    var arg2       = parameter.Name;
                                    var arg3       = parameter.ContainingSymbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat);
                                    var arg4       = FormatLiteralValues(filteredStrings);
                                    var diagnostic = operation.CreateDiagnostic(Rule, arg1, arg2, arg3, arg4);
                                    reportDiagnostic(diagnostic);
                                }
                            }
                        }
                    }

                    DataFlowAnalysisResult <ValueContentBlockAnalysisResult, ValueContentAbstractValue> ComputeValueContentAnalysisResult()
                    {
                        var cfg = operationBlockStartContext.OperationBlocks.GetControlFlowGraph();
                        if (cfg != null)
                        {
                            var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(operationBlockStartContext.Compilation);
                            return(ValueContentAnalysis.TryGetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider,
                                                                              operationBlockStartContext.Options, Rule, operationBlockStartContext.CancellationToken));
                        }

                        return(null);
                    }
                });
            });
        }
Example #5
0
        public override void Initialize(AnalysisContext context)
        {
            context.EnableConcurrentExecution();

            // Security analyzer - analyze and report diagnostics on generated code.
            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);

            context.RegisterCompilationStartAction(compilationStartAnalysisContext =>
            {
                var microsoftWindowsAzureStorageNamespaceSymbol = compilationStartAnalysisContext
                                                                  .Compilation
                                                                  .GlobalNamespace
                                                                  .GetMembers("Microsoft")
                                                                  .FirstOrDefault()
                                                                  ?.GetMembers("WindowsAzure")
                                                                  .OfType <INamespaceSymbol>()
                                                                  .FirstOrDefault()
                                                                  ?.GetMembers("Storage")
                                                                  .OfType <INamespaceSymbol>()
                                                                  .FirstOrDefault();

                if (microsoftWindowsAzureStorageNamespaceSymbol == null)
                {
                    return;
                }

                var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilationStartAnalysisContext.Compilation);

                wellKnownTypeProvider.TryGetTypeByMetadataName(
                    WellKnownTypeNames.MicrosoftWindowsAzureStorageCloudStorageAccount,
                    out INamedTypeSymbol cloudStorageAccountTypeSymbol);

                if (!wellKnownTypeProvider.TryGetTypeByMetadataName(WellKnownTypeNames.SystemNullable1, out INamedTypeSymbol nullableTypeSymbol) ||
                    !wellKnownTypeProvider.TryGetTypeByMetadataName(WellKnownTypeNames.MicrosoftWindowsAzureStorageSharedAccessProtocol, out INamedTypeSymbol sharedAccessProtocolTypeSymbol))
                {
                    return;
                }

                compilationStartAnalysisContext.RegisterOperationBlockStartAction(operationBlockStartContext =>
                {
                    var owningSymbol = operationBlockStartContext.OwningSymbol;
                    if (owningSymbol.IsConfiguredToSkipAnalysis(operationBlockStartContext.Options, Rule,
                                                                operationBlockStartContext.Compilation, operationBlockStartContext.CancellationToken))
                    {
                        return;
                    }

                    operationBlockStartContext.RegisterOperationAction(operationAnalysisContext =>
                    {
                        var invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation;
                        var methodSymbol        = invocationOperation.TargetMethod;

                        if (methodSymbol.Name != "GetSharedAccessSignature")
                        {
                            return;
                        }

                        var namespaceSymbol = methodSymbol.ContainingNamespace;

                        while (namespaceSymbol != null)
                        {
                            if (namespaceSymbol.Equals(microsoftWindowsAzureStorageNamespaceSymbol))
                            {
                                break;
                            }

                            namespaceSymbol = namespaceSymbol.ContainingNamespace;
                        }

                        if (namespaceSymbol == null)
                        {
                            return;
                        }

                        var typeSymbol = methodSymbol.ContainingType;

                        if (!typeSymbol.Equals(cloudStorageAccountTypeSymbol))
                        {
                            var protocolsArgumentOperation = invocationOperation.Arguments.FirstOrDefault(s => s.Parameter.Name == "protocols" &&
                                                                                                          s.Parameter.Type is INamedTypeSymbol namedTypeSymbol &&
                                                                                                          namedTypeSymbol.IsGenericType &&
                                                                                                          namedTypeSymbol.ConstructedFrom.Equals(nullableTypeSymbol) &&
                                                                                                          namedTypeSymbol.TypeArguments.Length == 1 &&
                                                                                                          namedTypeSymbol.TypeArguments.Contains(sharedAccessProtocolTypeSymbol));

                            if (protocolsArgumentOperation != null)
                            {
                                var cfg = invocationOperation.GetTopmostParentBlock()?.GetEnclosingControlFlowGraph();
                                if (cfg != null)
                                {
                                    var interproceduralAnalysisConfig = InterproceduralAnalysisConfiguration.Create(
                                        operationBlockStartContext.Options,
                                        SupportedDiagnostics,
                                        defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.None,
                                        cancellationToken: operationBlockStartContext.CancellationToken,
                                        defaultMaxInterproceduralMethodCallChain: 1);
                                    var valueContentAnalysisResult = ValueContentAnalysis.TryGetOrComputeResult(
                                        cfg,
                                        owningSymbol,
                                        operationAnalysisContext.Options,
                                        wellKnownTypeProvider,
                                        interproceduralAnalysisConfig,
                                        out var copyAnalysisResult,
                                        out var pointsToAnalysisResult);
                                    if (valueContentAnalysisResult == null)
                                    {
                                        return;
                                    }

                                    var protocolsArgument = valueContentAnalysisResult[protocolsArgumentOperation.Kind, protocolsArgumentOperation.Syntax];

                                    if (protocolsArgument.IsLiteralState &&
                                        !protocolsArgument.LiteralValues.Contains(SharedAccessProtocolHttpsOnly))
                                    {
                                        operationAnalysisContext.ReportDiagnostic(
                                            invocationOperation.CreateDiagnostic(
                                                Rule));
                                    }
                                }
                            }
                        }
                    }, OperationKind.Invocation);
                });
            });
        }
Example #6
0
        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 (options.IsConfiguredToSkipAnalysis(TaintedDataEnteringSinkDescriptor, owningSymbol, compilation))
                    {
                        return;
                    }

                    WellKnownTypeProvider wellKnownTypeProvider      = WellKnownTypeProvider.GetOrCreate(compilation);
                    Lazy <ControlFlowGraph?> controlFlowGraphFactory = new Lazy <ControlFlowGraph?>(
                        () => operationBlockStartContext.OperationBlocks.GetControlFlowGraph());
                    Lazy <PointsToAnalysisResult?> pointsToFactory = new Lazy <PointsToAnalysisResult?>(
                        () =>
                    {
                        if (controlFlowGraphFactory.Value == null)
                        {
                            return(null);
                        }

                        InterproceduralAnalysisConfiguration interproceduralAnalysisConfiguration = InterproceduralAnalysisConfiguration.Create(
                            options,
                            SupportedDiagnostics,
                            controlFlowGraphFactory.Value,
                            operationBlockStartContext.Compilation,
                            defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.ContextSensitive);
                        return(PointsToAnalysis.TryGetOrComputeResult(
                                   controlFlowGraphFactory.Value,
                                   owningSymbol,
                                   options,
                                   wellKnownTypeProvider,
                                   PointsToAnalysisKind.Complete,
                                   interproceduralAnalysisConfiguration,
                                   interproceduralAnalysisPredicate: null));
                    });
                    Lazy <(PointsToAnalysisResult?, ValueContentAnalysisResult?)> valueContentFactory = new Lazy <(PointsToAnalysisResult?, ValueContentAnalysisResult?)>(
                        () =>
                    {
                        if (controlFlowGraphFactory.Value == null)
                        {
                            return(null, null);
                        }

                        InterproceduralAnalysisConfiguration interproceduralAnalysisConfiguration = InterproceduralAnalysisConfiguration.Create(
                            options,
                            SupportedDiagnostics,
                            controlFlowGraphFactory.Value,
                            operationBlockStartContext.Compilation,
                            defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.ContextSensitive);
                        ValueContentAnalysisResult?valuecontentAnalysisResult = ValueContentAnalysis.TryGetOrComputeResult(
                            controlFlowGraphFactory.Value,
                            owningSymbol,
                            options,
                            wellKnownTypeProvider,
                            PointsToAnalysisKind.Complete,
                            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);

                    if (sourceInfoSymbolMap.RequiresParameterReferenceAnalysis)
                    {
                        operationBlockStartContext.RegisterOperationAction(
                            operationAnalysisContext =>
                        {
                            IParameterReferenceOperation parameterReferenceOperation = (IParameterReferenceOperation)operationAnalysisContext.Operation;
                            if (sourceInfoSymbolMap.IsSourceParameter(parameterReferenceOperation.Parameter, wellKnownTypeProvider))
                            {
                                lock (rootOperationsNeedingAnalysis)
                                {
                                    rootOperationsNeedingAnalysis.Add(parameterReferenceOperation.GetRoot());
                                }
                            }
                        },
                            OperationKind.ParameterReference);
                    }

                    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, arrayInitializerOperation))
                            {
                                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);
                                    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(compilationContext.CancellationToken);
                        }
                    });
                });
            });
        }
        private static TaintedDataAnalysisResult?TryGetOrComputeResult(
            ControlFlowGraph cfg,
            Compilation compilation,
            ISymbol containingMethod,
            AnalyzerOptions analyzerOptions,
            TaintedDataSymbolMap <SourceInfo> taintedSourceInfos,
            TaintedDataSymbolMap <SanitizerInfo> taintedSanitizerInfos,
            TaintedDataSymbolMap <SinkInfo> taintedSinkInfos,
            InterproceduralAnalysisConfiguration interproceduralAnalysisConfig)
        {
            if (cfg == null)
            {
                Debug.Fail("Expected non-null CFG");
                return(null);
            }

            WellKnownTypeProvider      wellKnownTypeProvider      = WellKnownTypeProvider.GetOrCreate(compilation);
            ValueContentAnalysisResult?valueContentAnalysisResult = null;
            CopyAnalysisResult?        copyAnalysisResult         = null;
            PointsToAnalysisResult?    pointsToAnalysisResult     = null;

            if (taintedSourceInfos.RequiresValueContentAnalysis || taintedSanitizerInfos.RequiresValueContentAnalysis || taintedSinkInfos.RequiresValueContentAnalysis)
            {
                valueContentAnalysisResult = ValueContentAnalysis.TryGetOrComputeResult(
                    cfg,
                    containingMethod,
                    analyzerOptions,
                    wellKnownTypeProvider,
                    PointsToAnalysisKind.Complete,
                    interproceduralAnalysisConfig,
                    out copyAnalysisResult,
                    out pointsToAnalysisResult,
                    pessimisticAnalysis: true,
                    performCopyAnalysis: false);
                if (valueContentAnalysisResult == null)
                {
                    return(null);
                }
            }
            else
            {
                pointsToAnalysisResult = PointsToAnalysis.TryGetOrComputeResult(
                    cfg,
                    containingMethod,
                    analyzerOptions,
                    wellKnownTypeProvider,
                    PointsToAnalysisKind.Complete,
                    interproceduralAnalysisConfig,
                    interproceduralAnalysisPredicate: null,
                    pessimisticAnalysis: true,
                    performCopyAnalysis: false);
                if (pointsToAnalysisResult == null)
                {
                    return(null);
                }
            }

            TaintedDataAnalysisContext analysisContext = TaintedDataAnalysisContext.Create(
                TaintedDataAbstractValueDomain.Default,
                wellKnownTypeProvider,
                cfg,
                containingMethod,
                analyzerOptions,
                interproceduralAnalysisConfig,
                pessimisticAnalysis: false,
                copyAnalysisResult: copyAnalysisResult,
                pointsToAnalysisResult: pointsToAnalysisResult,
                valueContentAnalysisResult: valueContentAnalysisResult,
                tryGetOrComputeAnalysisResult: TryGetOrComputeResultForAnalysisContext,
                taintedSourceInfos: taintedSourceInfos,
                taintedSanitizerInfos: taintedSanitizerInfos,
                taintedSinkInfos: taintedSinkInfos);

            return(TryGetOrComputeResultForAnalysisContext(analysisContext));
        }
        public override void Initialize(AnalysisContext context)
        {
            context.EnableConcurrentExecution();
            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);

            context.RegisterCompilationStartAction(compilationContext =>
            {
                compilationContext.RegisterOperationBlockAction(operationBlockContext =>
                {
                    var owningSymbol = operationBlockContext.OwningSymbol;
                    if (operationBlockContext.Options.IsConfiguredToSkipAnalysis(AlwaysTrueFalseOrNullRule, owningSymbol, operationBlockContext.Compilation, operationBlockContext.CancellationToken))
                    {
                        return;
                    }

                    var processedOperationRoots = new HashSet <IOperation>();

                    foreach (var operationRoot in operationBlockContext.OperationBlocks)
                    {
                        static bool ShouldAnalyze(IOperation op) =>
                        (op as IBinaryOperation)?.IsComparisonOperator() == true ||
                        (op as IInvocationOperation)?.TargetMethod.ReturnType.SpecialType == SpecialType.System_Boolean ||
                        op.Kind == OperationKind.Coalesce ||
                        op.Kind == OperationKind.ConditionalAccess ||
                        op.Kind == OperationKind.IsNull ||
                        op.Kind == OperationKind.IsPattern;

                        if (operationRoot.HasAnyOperationDescendant(ShouldAnalyze))
                        {
                            // Skip duplicate analysis from operation blocks for constructor initializer and body.
                            if (!processedOperationRoots.Add(operationRoot.GetRoot()))
                            {
                                // Already processed.
                                continue;
                            }

                            var cfg = operationBlockContext.GetControlFlowGraph(operationRoot);
                            var wellKnownTypeProvider      = WellKnownTypeProvider.GetOrCreate(operationBlockContext.Compilation);
                            var valueContentAnalysisResult = ValueContentAnalysis.TryGetOrComputeResult(cfg, owningSymbol, wellKnownTypeProvider,
                                                                                                        operationBlockContext.Options, AlwaysTrueFalseOrNullRule,
                                                                                                        PointsToAnalysisKind.Complete,
                                                                                                        operationBlockContext.CancellationToken,
                                                                                                        out var copyAnalysisResultOpt, out var pointsToAnalysisResult);
                            if (valueContentAnalysisResult == null ||
                                pointsToAnalysisResult == null)
                            {
                                continue;
                            }

                            foreach (var operation in cfg.DescendantOperations())
                            {
                                // Skip implicit operations.
                                // However, 'IsNull' operations are compiler generated operations corresponding to
                                // non-implicit conditional access operations, so we should not skip them.
                                if (operation.IsImplicit && operation.Kind != OperationKind.IsNull)
                                {
                                    continue;
                                }

                                switch (operation.Kind)
                                {
                                case OperationKind.BinaryOperator:
                                    var binaryOperation = (IBinaryOperation)operation;
                                    PredicateValueKind predicateKind = GetPredicateKind(binaryOperation);
                                    if (predicateKind != PredicateValueKind.Unknown &&
                                        (binaryOperation.LeftOperand is not IBinaryOperation leftBinary || GetPredicateKind(leftBinary) == PredicateValueKind.Unknown) &&
                                        (binaryOperation.RightOperand is not IBinaryOperation rightBinary || GetPredicateKind(rightBinary) == PredicateValueKind.Unknown))
                                    {
                                        ReportAlwaysTrueFalseOrNullDiagnostic(operation, predicateKind);
                                    }

                                    break;

                                case OperationKind.Invocation:
                                case OperationKind.IsPattern:
                                    predicateKind = GetPredicateKind(operation);
                                    if (predicateKind != PredicateValueKind.Unknown)
                                    {
                                        ReportAlwaysTrueFalseOrNullDiagnostic(operation, predicateKind);
                                    }

                                    break;

                                case OperationKind.IsNull:
                                    // '{0}' is always/never '{1}'. Remove or refactor the condition(s) to avoid dead code.
                                    predicateKind = GetPredicateKind(operation);
                                    DiagnosticDescriptor rule;
                                    switch (predicateKind)
                                    {
                                    case PredicateValueKind.AlwaysTrue:
                                        rule = AlwaysTrueFalseOrNullRule;
                                        break;

                                    case PredicateValueKind.AlwaysFalse:
                                        rule = NeverNullRule;
                                        break;

                                    default:
                                        continue;
                                    }

                                    var originalOperation = operationRoot.SemanticModel.GetOperation(operation.Syntax, operationBlockContext.CancellationToken);
                                    if (originalOperation is IAssignmentOperation or
                                        IVariableDeclaratorOperation)
                                    {
                                        // Skip compiler generated IsNull operation for assignment/variable declaration within a using.
                                        continue;
                                    }

                                    var arg1       = operation.Syntax.ToString();
                                    var arg2       = operation.Language == LanguageNames.VisualBasic ? "Nothing" : "null";
                                    var diagnostic = operation.CreateDiagnostic(rule, arg1, arg2);
                                    operationBlockContext.ReportDiagnostic(diagnostic);
                                    break;
                                }
                            }

                            PredicateValueKind GetPredicateKind(IOperation operation)
                            {
                                Debug.Assert(operation.Kind is OperationKind.BinaryOperator or
                                             OperationKind.Invocation or
                                             OperationKind.IsNull or
                                             OperationKind.IsPattern);
                                RoslynDebug.Assert(pointsToAnalysisResult != null);
                                RoslynDebug.Assert(valueContentAnalysisResult != null);

                                if (operation is IBinaryOperation binaryOperation &&
                                    binaryOperation.IsComparisonOperator() ||
                                    operation.Type?.SpecialType == SpecialType.System_Boolean)
                                {
                                    PredicateValueKind predicateKind = pointsToAnalysisResult.GetPredicateKind(operation);
                                    if (predicateKind != PredicateValueKind.Unknown)
                                    {
                                        return(predicateKind);
                                    }

                                    if (copyAnalysisResultOpt != null)
                                    {
                                        predicateKind = copyAnalysisResultOpt.GetPredicateKind(operation);
                                        if (predicateKind != PredicateValueKind.Unknown)
                                        {
                                            return(predicateKind);
                                        }
                                    }

                                    predicateKind = valueContentAnalysisResult.GetPredicateKind(operation);
                                    if (predicateKind != PredicateValueKind.Unknown)
                                    {
                                        return(predicateKind);
                                    }
                                }

                                return(PredicateValueKind.Unknown);
                            }

                            void ReportAlwaysTrueFalseOrNullDiagnostic(IOperation operation, PredicateValueKind predicateKind)
                            {
                                Debug.Assert(predicateKind != PredicateValueKind.Unknown);

                                // '{0}' is always '{1}'. Remove or refactor the condition(s) to avoid dead code.
                                var arg1 = operation.Syntax.ToString();
                                var arg2 = predicateKind == PredicateValueKind.AlwaysTrue ?
                                           (operation.Language == LanguageNames.VisualBasic ? "True" : "true") :
                                           (operation.Language == LanguageNames.VisualBasic ? "False" : "false");
                                var diagnostic = operation.CreateDiagnostic(AlwaysTrueFalseOrNullRule, arg1, arg2);
                                operationBlockContext.ReportDiagnostic(diagnostic);
                            }
                        }
                    }
        /// <summary>
        /// Analyzers should use <see cref="BatchGetOrComputeHazardousUsages"/> instead.  Gets hazardous usages of an object based on a set of its properties.
        /// </summary>
        /// <param name="cfg">Control flow graph of the code.</param>
        /// <param name="compilation">Compilation containing the code.</param>
        /// <param name="owningSymbol">Symbol of the code to examine.</param>
        /// <param name="typeToTrackMetadataName">Name of the type to track.</param>
        /// <param name="constructorMapper">How constructor invocations map to <see cref="PropertySetAbstractValueKind"/>s.</param>
        /// <param name="propertyMappers">How property assignments map to <see cref="PropertySetAbstractValueKind"/>.</param>
        /// <param name="hazardousUsageEvaluators">When and how to evaluate <see cref="PropertySetAbstractValueKind"/>s to for hazardous usages.</param>
        /// <param name="interproceduralAnalysisConfig">Interprocedural dataflow analysis configuration.</param>
        /// <param name="pessimisticAnalysis">Whether to be pessimistic.</param>
        /// <returns>Property set analysis result.</returns>
        internal static PropertySetAnalysisResult GetOrComputeResult(
            ControlFlowGraph cfg,
            Compilation compilation,
            ISymbol owningSymbol,
            AnalyzerOptions analyzerOptions,
            string typeToTrackMetadataName,
            ConstructorMapper constructorMapper,
            PropertyMapperCollection propertyMappers,
            HazardousUsageEvaluatorCollection hazardousUsageEvaluators,
            InterproceduralAnalysisConfiguration interproceduralAnalysisConfig,
            bool pessimisticAnalysis = false)
        {
            if (constructorMapper == null)
            {
                throw new ArgumentNullException(nameof(constructorMapper));
            }

            if (propertyMappers == null)
            {
                throw new ArgumentNullException(nameof(propertyMappers));
            }

            if (hazardousUsageEvaluators == null)
            {
                throw new ArgumentNullException(nameof(hazardousUsageEvaluators));
            }

            constructorMapper.Validate(propertyMappers.PropertyValuesCount);

            var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilation);

            PointsToAnalysisResult     pointsToAnalysisResult;
            ValueContentAnalysisResult valueContentAnalysisResultOpt;

            if (!constructorMapper.RequiresValueContentAnalysis && !propertyMappers.RequiresValueContentAnalysis)
            {
                pointsToAnalysisResult = PointsToAnalysis.TryGetOrComputeResult(
                    cfg,
                    owningSymbol,
                    analyzerOptions,
                    wellKnownTypeProvider,
                    interproceduralAnalysisConfig,
                    interproceduralAnalysisPredicateOpt: null,
                    pessimisticAnalysis,
                    performCopyAnalysis: false);
                if (pointsToAnalysisResult == null)
                {
                    return(null);
                }

                valueContentAnalysisResultOpt = null;
            }
            else
            {
                valueContentAnalysisResultOpt = ValueContentAnalysis.TryGetOrComputeResult(
                    cfg,
                    owningSymbol,
                    analyzerOptions,
                    wellKnownTypeProvider,
                    interproceduralAnalysisConfig,
                    out var copyAnalysisResult,
                    out pointsToAnalysisResult,
                    pessimisticAnalysis,
                    performCopyAnalysis: false);
                if (valueContentAnalysisResultOpt == null)
                {
                    return(null);
                }
            }

            var analysisContext = PropertySetAnalysisContext.Create(
                PropertySetAbstractValueDomain.Default,
                wellKnownTypeProvider,
                cfg,
                owningSymbol,
                analyzerOptions,
                interproceduralAnalysisConfig,
                pessimisticAnalysis,
                pointsToAnalysisResult,
                valueContentAnalysisResultOpt,
                TryGetOrComputeResultForAnalysisContext,
                typeToTrackMetadataName,
                constructorMapper,
                propertyMappers,
                hazardousUsageEvaluators);
            var result = TryGetOrComputeResultForAnalysisContext(analysisContext);

            return(result);
        }
Example #10
0
        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)
        {
            if (!Debugger.IsAttached) // prefer single thread for debugging in development
            {
                context.EnableConcurrentExecution();
            }

            if (context.IsAuditMode())
            {
                context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
            }
            else
            {
                context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
            }

            context.RegisterCompilationStartAction(
                (CompilationStartAnalysisContext compilationContext) =>
            {
                var config = Configuration.GetOrCreate(compilationContext);

                if (config.AuditMode)
                {
                    TaintedDataSymbolMap <SinkInfo> sinkInfoSymbolMap = config.TaintConfiguration.GetSinkSymbolMap(this.SinkKind);
                    if (sinkInfoSymbolMap.IsEmpty)
                    {
                        return;
                    }

                    Compilation compilation = compilationContext.Compilation;
                    compilationContext.RegisterOperationBlockStartAction(
                        operationBlockStartContext =>
                    {
                        ISymbol owningSymbol                = operationBlockStartContext.OwningSymbol;
                        AnalyzerOptions options             = operationBlockStartContext.Options;
                        CancellationToken cancellationToken = operationBlockStartContext.CancellationToken;
                        if (options.IsConfiguredToSkipAnalysis(TaintedDataEnteringSinkDescriptor, owningSymbol, compilation, cancellationToken))
                        {
                            return;
                        }

                        WellKnownTypeProvider wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilation);

                        void CreateWarning(OperationAnalysisContext operationAnalysisContext, Location location, ISymbol paramSymbol, ISymbol symbol)
                        {
                            // 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,
                                location,
                                additionalLocations: new Location[] { location },
                                messageArgs: new object[] {
                                paramSymbol.Name,
                                symbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat),
                                symbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat),
                                symbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat)
                            });
                            operationAnalysisContext.ReportDiagnostic(diagnostic);
                        }

                        bool IsConstant(IOperation operation, IOperation value, OperationAnalysisContext operationAnalysisContext)
                        {
                            if (value.ConstantValue.HasValue || value is ITypeOfOperation)
                            {
                                return(true);
                            }

                            if (!operation.TryGetEnclosingControlFlowGraph(out var cfg))
                            {
                                return(false);
                            }

                            var valueContentResult = ValueContentAnalysis.TryGetOrComputeResult(cfg, owningSymbol, wellKnownTypeProvider,
                                                                                                operationAnalysisContext.Options, TaintedDataEnteringSinkDescriptor, PointsToAnalysisKind.Complete, operationAnalysisContext.CancellationToken);
                            if (valueContentResult == null)
                            {
                                return(false);
                            }

                            ValueContentAbstractValue abstractValue = valueContentResult[value.Kind, value.Syntax];
                            return(abstractValue.NonLiteralState == ValueContainsNonLiteralState.No);
                        }

                        operationBlockStartContext.RegisterOperationAction(
                            operationAnalysisContext =>
                        {
                            IAssignmentOperation operation = (IAssignmentOperation)operationAnalysisContext.Operation;
                            if (!(operation.Target is IPropertyReferenceOperation propertyReferenceOperation))
                            {
                                return;
                            }

                            IEnumerable <SinkInfo>?infosForType = sinkInfoSymbolMap.GetInfosForType(propertyReferenceOperation.Member.ContainingType);
                            if (infosForType != null &&
                                infosForType.Any(x => x.SinkProperties.Contains(propertyReferenceOperation.Member.MetadataName)) &&
                                !IsConstant(operation, operation.Value, operationAnalysisContext))
                            {
                                CreateWarning(
                                    operationAnalysisContext,
                                    propertyReferenceOperation.Syntax.GetLocation(),
                                    operation.Value.Type,
                                    propertyReferenceOperation.Member);
                            }
                        },
                            OperationKind.SimpleAssignment);

                        operationBlockStartContext.RegisterOperationAction(
                            operationAnalysisContext =>
                        {
                            IInvocationOperation invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation;
                            IEnumerable <SinkInfo>?infosForType      = sinkInfoSymbolMap.GetInfosForType(invocationOperation.TargetMethod.ContainingType);
                            if (infosForType == null)
                            {
                                return;
                            }

                            foreach (SinkInfo sinkInfo in infosForType)
                            {
                                foreach (IArgumentOperation taintedArgument in invocationOperation.Arguments.Where(x => !IsConstant(x, x.Value, operationAnalysisContext)))
                                {
                                    if (sinkInfo.SinkMethodParameters.TryGetValue(invocationOperation.TargetMethod.MetadataName, out ImmutableHashSet <string> sinkParameters) &&
                                        sinkParameters.Contains(taintedArgument.Parameter.MetadataName))
                                    {
                                        CreateWarning(operationAnalysisContext, invocationOperation.Syntax.GetLocation(), taintedArgument.Parameter, invocationOperation.TargetMethod);
                                        return;
                                    }
                                }
                            }
                        },
                            OperationKind.Invocation);

                        operationBlockStartContext.RegisterOperationAction(
                            operationAnalysisContext =>
                        {
                            IObjectCreationOperation invocationOperation = (IObjectCreationOperation)operationAnalysisContext.Operation;
                            IEnumerable <SinkInfo>?infosForType          = sinkInfoSymbolMap.GetInfosForType(invocationOperation.Constructor.ContainingType);
                            if (infosForType == null)
                            {
                                return;
                            }

                            foreach (SinkInfo sinkInfo in infosForType)
                            {
                                foreach (IArgumentOperation taintedArgument in invocationOperation.Arguments.Where(x => !IsConstant(x, x.Value, operationAnalysisContext)))
                                {
                                    if (sinkInfo.IsAnyStringParameterInConstructorASink &&
                                        taintedArgument.Parameter.Type.SpecialType == SpecialType.System_String)
                                    {
                                        CreateWarning(operationAnalysisContext, invocationOperation.Syntax.GetLocation(), taintedArgument.Parameter, invocationOperation.Constructor);
                                        return;
                                    }
                                    else if (sinkInfo.SinkMethodParameters.TryGetValue(invocationOperation.Constructor.MetadataName, out ImmutableHashSet <string> sinkParameters) &&
                                             sinkParameters.Contains(taintedArgument.Parameter.MetadataName))
                                    {
                                        CreateWarning(operationAnalysisContext, invocationOperation.Syntax.GetLocation(), taintedArgument.Parameter, invocationOperation.Constructor);
                                        return;
                                    }
                                }
                            }
                        },
                            OperationKind.ObjectCreation);
                    });
                }
                else
                {
                    TaintedDataSymbolMap <SourceInfo> sourceInfoSymbolMap = config.TaintConfiguration.GetSourceSymbolMap(this.SinkKind);
                    if (sourceInfoSymbolMap.IsEmpty)
                    {
                        return;
                    }

                    TaintedDataSymbolMap <SinkInfo> sinkInfoSymbolMap = config.TaintConfiguration.GetSinkSymbolMap(this.SinkKind);
                    if (sinkInfoSymbolMap.IsEmpty)
                    {
                        return;
                    }

                    Compilation compilation = compilationContext.Compilation;
                    compilationContext.RegisterOperationBlockStartAction(
                        operationBlockStartContext =>
                    {
                        ISymbol owningSymbol                = operationBlockStartContext.OwningSymbol;
                        AnalyzerOptions options             = operationBlockStartContext.Options;
                        CancellationToken cancellationToken = operationBlockStartContext.CancellationToken;
                        if (options.IsConfiguredToSkipAnalysis(TaintedDataEnteringSinkDescriptor, owningSymbol, compilation, cancellationToken))
                        {
                            return;
                        }

                        WellKnownTypeProvider wellKnownTypeProvider      = WellKnownTypeProvider.GetOrCreate(compilation);
                        Lazy <ControlFlowGraph?> controlFlowGraphFactory = new Lazy <ControlFlowGraph?>(
                            () => operationBlockStartContext.OperationBlocks.GetControlFlowGraph());
                        Lazy <PointsToAnalysisResult?> pointsToFactory = new Lazy <PointsToAnalysisResult?>(
                            () =>
                        {
                            if (controlFlowGraphFactory.Value == null)
                            {
                                return(null);
                            }

                            InterproceduralAnalysisConfiguration interproceduralAnalysisConfiguration = InterproceduralAnalysisConfiguration.Create(
                                options,
                                SupportedDiagnostics,
                                controlFlowGraphFactory.Value,
                                operationBlockStartContext.Compilation,
                                defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.ContextSensitive,
                                cancellationToken: cancellationToken,
                                defaultMaxInterproceduralMethodCallChain: config.MaxInterproceduralMethodCallChain,
                                defaultMaxInterproceduralLambdaOrLocalFunctionCallChain: config.MaxInterproceduralLambdaOrLocalFunctionCallChain);
                            return(PointsToAnalysis.TryGetOrComputeResult(
                                       controlFlowGraphFactory.Value,
                                       owningSymbol,
                                       options,
                                       wellKnownTypeProvider,
                                       PointsToAnalysisKind.Complete,
                                       interproceduralAnalysisConfiguration,
                                       interproceduralAnalysisPredicate: null));
                        });
                        Lazy <(PointsToAnalysisResult?, ValueContentAnalysisResult?)> valueContentFactory = new Lazy <(PointsToAnalysisResult?, ValueContentAnalysisResult?)>(
                            () =>
                        {
                            if (controlFlowGraphFactory.Value == null)
                            {
                                return(null, null);
                            }

                            InterproceduralAnalysisConfiguration interproceduralAnalysisConfiguration = InterproceduralAnalysisConfiguration.Create(
                                options,
                                SupportedDiagnostics,
                                controlFlowGraphFactory.Value,
                                operationBlockStartContext.Compilation,
                                defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.ContextSensitive,
                                cancellationToken: cancellationToken,
                                defaultMaxInterproceduralMethodCallChain: config.MaxInterproceduralMethodCallChain,
                                defaultMaxInterproceduralLambdaOrLocalFunctionCallChain: config.MaxInterproceduralLambdaOrLocalFunctionCallChain);
                            ValueContentAnalysisResult?valuecontentAnalysisResult = ValueContentAnalysis.TryGetOrComputeResult(
                                controlFlowGraphFactory.Value,
                                owningSymbol,
                                options,
                                wellKnownTypeProvider,
                                PointsToAnalysisKind.Complete,
                                interproceduralAnalysisConfiguration,
                                out _,
                                out PointsToAnalysisResult? p);

                            return(p, valuecontentAnalysisResult);
                        });

                        var 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);

                        if (sourceInfoSymbolMap.RequiresFieldReferenceAnalysis)
                        {
                            operationBlockStartContext.RegisterOperationAction(
                                operationAnalysisContext =>
                            {
                                IFieldReferenceOperation fieldReferenceOperation = (IFieldReferenceOperation)operationAnalysisContext.Operation;
                                if (sourceInfoSymbolMap.IsSourceField(fieldReferenceOperation.Field))
                                {
                                    lock (rootOperationsNeedingAnalysis)
                                    {
                                        rootOperationsNeedingAnalysis.Add(fieldReferenceOperation.GetRoot());
                                    }
                                }
                            },
                                OperationKind.FieldReference);
                        }

                        if (sourceInfoSymbolMap.RequiresParameterReferenceAnalysis)
                        {
                            operationBlockStartContext.RegisterOperationAction(
                                operationAnalysisContext =>
                            {
                                IParameterReferenceOperation parameterReferenceOperation = (IParameterReferenceOperation)operationAnalysisContext.Operation;
                                if (sourceInfoSymbolMap.IsSourceParameter(parameterReferenceOperation.Parameter, wellKnownTypeProvider))
                                {
                                    lock (rootOperationsNeedingAnalysis)
                                    {
                                        rootOperationsNeedingAnalysis.Add(parameterReferenceOperation.GetRoot());
                                    }
                                }
                            },
                                OperationKind.ParameterReference);
                        }

                        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 (config.TaintConfiguration.HasTaintArraySource(SinkKind, config))
                        {
                            operationBlockStartContext.RegisterOperationAction(
                                operationAnalysisContext =>
                            {
                                IArrayInitializerOperation arrayInitializerOperation = (IArrayInitializerOperation)operationAnalysisContext.Operation;
                                if (arrayInitializerOperation.GetAncestor <IArrayCreationOperation>(OperationKind.ArrayCreation)?.Type is IArrayTypeSymbol arrayTypeSymbol &&
                                    sourceInfoSymbolMap.IsSourceConstantArrayOfType(arrayTypeSymbol, arrayInitializerOperation))
                                {
                                    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,
                                            config.TaintConfiguration.GetSanitizerSymbolMap(this.SinkKind),
                                            sinkInfoSymbolMap,
                                            operationBlockAnalysisContext.CancellationToken,
                                            config.MaxInterproceduralMethodCallChain,
                                            config.MaxInterproceduralLambdaOrLocalFunctionCallChain);
                                        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.Name,
                                                    sourceSink.Sink.AccessingMethod.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat),
                                                    sourceOrigin.Symbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat),
                                                    sourceOrigin.AccessingMethod.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat)
                                                });
                                                operationBlockAnalysisContext.ReportDiagnostic(diagnostic);
                                            }
                                        }
                                    }
                                }
                            }
                            finally
                            {
                                rootOperationsNeedingAnalysis.Free(compilationContext.CancellationToken);
                            }
                        });
                    });
                }
            });
        }
Example #12
0
        public override void Initialize(AnalysisContext context)
        {
            if (!Debugger.IsAttached) // prefer single thread for debugging in development
            {
                context.EnableConcurrentExecution();
            }

            if (context.IsAuditMode())
            {
                context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
            }
            else
            {
                context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
            }

            context.RegisterCompilationStartAction(
                (CompilationStartAnalysisContext compilationContext) =>
            {
                var config = Configuration.GetOrCreate(compilationContext);

                TaintedDataSymbolMap <SinkInfo> sinkInfoSymbolMap = config.TaintConfiguration.GetSinkSymbolMap(this.SinkKind);
                if (sinkInfoSymbolMap.IsEmpty)
                {
                    return;
                }

                Compilation compilation = compilationContext.Compilation;
                compilationContext.RegisterOperationBlockStartAction(
                    operationBlockStartContext =>
                {
                    ISymbol owningSymbol                = operationBlockStartContext.OwningSymbol;
                    AnalyzerOptions options             = operationBlockStartContext.Options;
                    CancellationToken cancellationToken = operationBlockStartContext.CancellationToken;
                    if (options.IsConfiguredToSkipAnalysis(TaintedDataEnteringSinkDescriptor, owningSymbol, compilation, cancellationToken))
                    {
                        return;
                    }

                    WellKnownTypeProvider wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilation);
                    var warnings = PooledHashSet <Location> .GetInstance();

                    void CreateWarning(OperationAnalysisContext operationAnalysisContext, Location location, ISymbol symbol)
                    {
                        warnings.Add(location);

                        Diagnostic diagnostic = Diagnostic.Create(
                            this.TaintedDataEnteringSinkDescriptor,
                            location,
                            additionalLocations: new Location[] { location },
                            messageArgs: new object[] {
                            symbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat),
                        });
                        operationAnalysisContext.ReportDiagnostic(diagnostic);
                    }

                    bool IsHardcoded(IOperation operation, IOperation value, OperationAnalysisContext operationAnalysisContext)
                    {
                        bool IsEmptyString(object?value)
                        {
                            return(Equals(value, null) || Equals(value, string.Empty));
                        }

                        if (value.ConstantValue.HasValue && !IsEmptyString(value.ConstantValue.Value))
                        {
                            return(true);
                        }

                        if (value.Kind == OperationKind.ArrayCreation &&
                            value is IArrayCreationOperation arrayValue &&
                            arrayValue.Initializer?.Children.All(x => x.ConstantValue.HasValue) == true)
                        {
                            return(true);
                        }

                        if (!operation.TryGetEnclosingControlFlowGraph(out var cfg))
                        {
                            return(false);
                        }

                        var valueContentResult = ValueContentAnalysis.TryGetOrComputeResult(cfg, owningSymbol, wellKnownTypeProvider,
                                                                                            operationAnalysisContext.Options, TaintedDataEnteringSinkDescriptor, PointsToAnalysisKind.Complete, operationAnalysisContext.CancellationToken);
                        if (valueContentResult == null)
                        {
                            return(false);
                        }

                        ValueContentAbstractValue abstractValue = valueContentResult[value.Kind, value.Syntax];
                        if (abstractValue.NonLiteralState != ValueContainsNonLiteralState.No)
                        {
                            return(false);
                        }

                        if (abstractValue.LiteralValues.All(IsEmptyString))
                        {
                            return(false);
                        }

                        return(true);
                    }

                    var rootOperationsNeedingAnalysis = PooledHashSet <IOperation> .GetInstance();
                    var sourceInfosBuilder            = PooledHashSet <SourceInfo> .GetInstance();

                    Lazy <ControlFlowGraph?> controlFlowGraphFactory = new Lazy <ControlFlowGraph?>(
                        () => operationBlockStartContext.OperationBlocks.GetControlFlowGraph());

                    operationBlockStartContext.RegisterOperationAction(
                        operationAnalysisContext =>
                    {
                        var operation = (IFieldReferenceOperation)operationAnalysisContext.Operation;
                        if ((operation.Field.IsConst && operation.ConstantValue.HasValue) ||
                            operation.Field.IsReadOnly /* huge assumption that it is set to a hardcoded value in initializer or constructor */)
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                rootOperationsNeedingAnalysis.Add(operationAnalysisContext.Operation.GetRoot());
                                sourceInfosBuilder.AddSourceInfo(
                                    operation.Field.ContainingType.ToString(),
                                    isInterface: false,
                                    taintedProperties: null,
                                    taintedFields: Enumerable.Repeat(operation.Field.Name, 1),
                                    taintedMethods: null);
                            }
                        }
                    },
                        OperationKind.FieldReference);

                    operationBlockStartContext.RegisterOperationBlockEndAction(
                        operationBlockAnalysisContext =>
                    {
                        try
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                if (!rootOperationsNeedingAnalysis.Any())
                                {
                                    return;
                                }

                                if (controlFlowGraphFactory.Value == null)
                                {
                                    return;
                                }

                                var sourceInfos = sourceInfosBuilder.ToImmutable();

                                foreach (IOperation rootOperation in rootOperationsNeedingAnalysis)
                                {
                                    TaintedDataAnalysisResult?taintedDataAnalysisResult = TaintedDataAnalysis.TryGetOrComputeResult(
                                        controlFlowGraphFactory.Value,
                                        operationBlockAnalysisContext.Compilation,
                                        operationBlockAnalysisContext.OwningSymbol,
                                        operationBlockAnalysisContext.Options,
                                        TaintedDataEnteringSinkDescriptor,
                                        new TaintedDataSymbolMap <SourceInfo>(wellKnownTypeProvider, sourceInfos),
                                        config.TaintConfiguration.GetSanitizerSymbolMap(this.SinkKind),
                                        sinkInfoSymbolMap,
                                        operationBlockAnalysisContext.CancellationToken,
                                        config.MaxInterproceduralMethodCallChain,
                                        config.MaxInterproceduralLambdaOrLocalFunctionCallChain);

                                    if (taintedDataAnalysisResult == null)
                                    {
                                        return;
                                    }

                                    foreach (TaintedDataSourceSink sourceSink in taintedDataAnalysisResult.TaintedDataSourceSinks)
                                    {
                                        if (!sourceSink.SinkKinds.Contains(this.SinkKind))
                                        {
                                            continue;
                                        }

                                        foreach (SymbolAccess sourceOrigin in sourceSink.SourceOrigins)
                                        {
                                            if (warnings.Contains(sourceSink.Sink.Location))
                                            {
                                                continue;
                                            }

                                            Diagnostic diagnostic = Diagnostic.Create(
                                                this.TaintedDataEnteringSinkDescriptor,
                                                sourceSink.Sink.Location,
                                                additionalLocations: new Location[] { sourceOrigin.Location },
                                                messageArgs: new object[] {
                                                sourceSink.Sink.Symbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat)
                                            });
                                            operationBlockAnalysisContext.ReportDiagnostic(diagnostic);
                                        }
                                    }
                                }
                            }
                        }
                        finally
                        {
                            warnings.Free(compilationContext.CancellationToken);
                            sourceInfosBuilder.Free(compilationContext.CancellationToken);
                            rootOperationsNeedingAnalysis.Free(compilationContext.CancellationToken);
                        }
                    });

                    operationBlockStartContext.RegisterOperationAction(
                        operationAnalysisContext =>
                    {
                        var operation = (IAssignmentOperation)operationAnalysisContext.Operation;
                        if (!(operation.Target is IPropertyReferenceOperation propertyReferenceOperation))
                        {
                            return;
                        }

                        IEnumerable <SinkInfo>?infosForType = sinkInfoSymbolMap.GetInfosForType(propertyReferenceOperation.Member.ContainingType);
                        if (infosForType != null &&
                            infosForType.Any(x => x.SinkProperties.Contains(propertyReferenceOperation.Member.MetadataName)) &&
                            IsHardcoded(operation, operation.Value, operationAnalysisContext))
                        {
                            CreateWarning(
                                operationAnalysisContext,
                                propertyReferenceOperation.Syntax.GetLocation(),
                                propertyReferenceOperation.Member);
                        }
                    },
                        OperationKind.SimpleAssignment);

                    operationBlockStartContext.RegisterOperationAction(
                        operationAnalysisContext =>
                    {
                        var invocationOperation             = (IInvocationOperation)operationAnalysisContext.Operation;
                        IEnumerable <SinkInfo>?infosForType = sinkInfoSymbolMap.GetInfosForType(invocationOperation.TargetMethod.ContainingType);
                        if (infosForType == null)
                        {
                            return;
                        }

                        foreach (SinkInfo sinkInfo in infosForType)
                        {
                            foreach (IArgumentOperation taintedArgument in invocationOperation.Arguments.Where(x => IsHardcoded(x, x.Value, operationAnalysisContext)))
                            {
                                if (sinkInfo.SinkMethodParameters.TryGetValue(invocationOperation.TargetMethod.MetadataName, out ImmutableHashSet <string> sinkParameters) &&
                                    sinkParameters.Contains(taintedArgument.Parameter.MetadataName))
                                {
                                    CreateWarning(
                                        operationAnalysisContext,
                                        invocationOperation.Syntax.GetLocation(),
                                        invocationOperation.TargetMethod);
                                    return;
                                }
                            }
                        }
                    },
                        OperationKind.Invocation);

                    operationBlockStartContext.RegisterOperationAction(
                        operationAnalysisContext =>
                    {
                        var invocationOperation             = (IObjectCreationOperation)operationAnalysisContext.Operation;
                        IEnumerable <SinkInfo>?infosForType = sinkInfoSymbolMap.GetInfosForType(invocationOperation.Constructor.ContainingType);
                        if (infosForType == null)
                        {
                            return;
                        }

                        foreach (SinkInfo sinkInfo in infosForType)
                        {
                            foreach (IArgumentOperation taintedArgument in invocationOperation.Arguments.Where(x => IsHardcoded(x, x.Value, operationAnalysisContext)))
                            {
                                if (sinkInfo.IsAnyStringParameterInConstructorASink &&
                                    taintedArgument.Parameter.Type.SpecialType == SpecialType.System_String)
                                {
                                    CreateWarning(
                                        operationAnalysisContext,
                                        invocationOperation.Syntax.GetLocation(),
                                        taintedArgument.Parameter);
                                    return;
                                }
                                else if (sinkInfo.SinkMethodParameters.TryGetValue(invocationOperation.Constructor.MetadataName, out ImmutableHashSet <string> sinkParameters) &&
                                         sinkParameters.Contains(taintedArgument.Parameter.MetadataName))
                                {
                                    CreateWarning(
                                        operationAnalysisContext,
                                        invocationOperation.Syntax.GetLocation(),
                                        taintedArgument.Parameter);
                                    return;
                                }
                            }
                        }
                    },
                        OperationKind.ObjectCreation);
                });
            });
        }
        public override void Initialize(AnalysisContext context)
        {
            if (!Debugger.IsAttached) // prefer single thread for debugging in development
            {
                context.EnableConcurrentExecution();
            }

            if (context.IsAuditMode())
            {
                context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
            }
            else
            {
                context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
            }

            context.RegisterCompilationStartAction(
                (CompilationStartAnalysisContext compilationContext) =>
            {
                var config = Configuration.GetOrCreate(compilationContext);

                TaintedDataSymbolMap <SinkInfo> sinkInfoSymbolMap = config.TaintConfiguration.GetSinkSymbolMap(this.SinkKind);
                if (sinkInfoSymbolMap.IsEmpty)
                {
                    return;
                }

                Compilation compilation = compilationContext.Compilation;
                compilationContext.RegisterOperationBlockStartAction(
                    operationBlockStartContext =>
                {
                    ISymbol owningSymbol                = operationBlockStartContext.OwningSymbol;
                    AnalyzerOptions options             = operationBlockStartContext.Options;
                    CancellationToken cancellationToken = operationBlockStartContext.CancellationToken;
                    if (options.IsConfiguredToSkipAnalysis(TaintedDataEnteringSinkDescriptor, owningSymbol, compilation, cancellationToken))
                    {
                        return;
                    }

                    WellKnownTypeProvider wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilation);
                    var warnings = PooledHashSet <Location> .GetInstance();

                    void CreateWarning(OperationAnalysisContext operationAnalysisContext, Location location, ISymbol symbol)
                    {
                        warnings.Add(location);

                        Diagnostic diagnostic = Diagnostic.Create(
                            this.TaintedDataEnteringSinkDescriptor,
                            location,
                            additionalLocations: new Location[] { location },
                            messageArgs: new object[] {
                            symbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat),
                        });
                        operationAnalysisContext.ReportDiagnostic(diagnostic);
                    }

                    bool IsHardcoded(IOperation operation, IOperation value, OperationAnalysisContext operationAnalysisContext)
                    {
                        bool IsEmptyString(object?value)
                        {
                            return(Equals(value, null) || Equals(value, string.Empty));
                        }

                        if (value.ConstantValue.HasValue && !IsEmptyString(value.ConstantValue.Value))
                        {
                            return(true);
                        }

                        if (value.Kind == OperationKind.ArrayCreation &&
                            value is IArrayCreationOperation arrayValue &&
                            arrayValue.Initializer?.Children.All(x => x.ConstantValue.HasValue) == true)
                        {
                            return(true);
                        }

                        if (!operation.TryGetEnclosingControlFlowGraph(out var cfg))
                        {
                            return(false);
                        }

                        var valueContentResult = ValueContentAnalysis.TryGetOrComputeResult(cfg, owningSymbol, wellKnownTypeProvider,
                                                                                            operationAnalysisContext.Options, TaintedDataEnteringSinkDescriptor, PointsToAnalysisKind.Complete, operationAnalysisContext.CancellationToken);
                        if (valueContentResult == null)
                        {
                            return(false);
                        }

                        ValueContentAbstractValue abstractValue = valueContentResult[value.Kind, value.Syntax];
                        if (abstractValue.NonLiteralState != ValueContainsNonLiteralState.No)
                        {
                            return(false);
                        }

                        if (abstractValue.LiteralValues.All(IsEmptyString))
                        {
                            return(false);
                        }

                        return(true);
                    }

                    operationBlockStartContext.RegisterOperationAction(
                        operationAnalysisContext =>
                    {
                        var operation = (IAssignmentOperation)operationAnalysisContext.Operation;
                        if (!(operation.Target is IPropertyReferenceOperation propertyReferenceOperation))
                        {
                            return;
                        }

                        IEnumerable <SinkInfo>?infosForType = sinkInfoSymbolMap.GetInfosForType(propertyReferenceOperation.Member.ContainingType);
                        if (infosForType != null &&
                            infosForType.Any(x => x.SinkProperties.Contains(propertyReferenceOperation.Member.MetadataName)) &&
                            IsHardcoded(operation, operation.Value, operationAnalysisContext))
                        {
                            CreateWarning(
                                operationAnalysisContext,
                                propertyReferenceOperation.Syntax.GetLocation(),
                                propertyReferenceOperation.Member);
                        }
                    },
                        OperationKind.SimpleAssignment);

                    operationBlockStartContext.RegisterOperationAction(
                        operationAnalysisContext =>
                    {
                        var invocationOperation             = (IInvocationOperation)operationAnalysisContext.Operation;
                        IEnumerable <SinkInfo>?infosForType = sinkInfoSymbolMap.GetInfosForType(invocationOperation.TargetMethod.ContainingType);
                        if (infosForType == null)
                        {
                            return;
                        }

                        foreach (SinkInfo sinkInfo in infosForType)
                        {
                            foreach (IArgumentOperation taintedArgument in invocationOperation.Arguments.Where(x => IsHardcoded(x, x.Value, operationAnalysisContext)))
                            {
                                if (sinkInfo.SinkMethodParameters.TryGetValue(invocationOperation.TargetMethod.MetadataName, out ImmutableHashSet <string> sinkParameters) &&
                                    sinkParameters.Contains(taintedArgument.Parameter.MetadataName))
                                {
                                    CreateWarning(
                                        operationAnalysisContext,
                                        invocationOperation.Syntax.GetLocation(),
                                        invocationOperation.TargetMethod);
                                    return;
                                }
                            }
                        }
                    },
                        OperationKind.Invocation);

                    operationBlockStartContext.RegisterOperationAction(
                        operationAnalysisContext =>
                    {
                        var invocationOperation             = (IObjectCreationOperation)operationAnalysisContext.Operation;
                        IEnumerable <SinkInfo>?infosForType = sinkInfoSymbolMap.GetInfosForType(invocationOperation.Constructor.ContainingType);
                        if (infosForType == null)
                        {
                            return;
                        }

                        foreach (SinkInfo sinkInfo in infosForType)
                        {
                            foreach (IArgumentOperation taintedArgument in invocationOperation.Arguments.Where(x => IsHardcoded(x, x.Value, operationAnalysisContext)))
                            {
                                if (sinkInfo.IsAnyStringParameterInConstructorASink &&
                                    taintedArgument.Parameter.Type.SpecialType == SpecialType.System_String)
                                {
                                    CreateWarning(
                                        operationAnalysisContext,
                                        invocationOperation.Syntax.GetLocation(),
                                        taintedArgument.Parameter);
                                    return;
                                }
                                else if (sinkInfo.SinkMethodParameters.TryGetValue(invocationOperation.Constructor.MetadataName, out ImmutableHashSet <string> sinkParameters) &&
                                         sinkParameters.Contains(taintedArgument.Parameter.MetadataName))
                                {
                                    CreateWarning(
                                        operationAnalysisContext,
                                        invocationOperation.Syntax.GetLocation(),
                                        taintedArgument.Parameter);
                                    return;
                                }
                            }
                        }
                    },
                        OperationKind.ObjectCreation);
                });
            });
        }
        public override void Initialize(AnalysisContext context)
        {
            if (!Debugger.IsAttached) // prefer single thread for debugging in development
            {
                context.EnableConcurrentExecution();
            }

            if (context.IsAuditMode())
            {
                context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
            }
            else
            {
                context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
            }

            if (!Debugger.IsAttached) // prefer single thread for debugging in development
            {
                context.EnableConcurrentExecution();
            }

            if (context.IsAuditMode())
            {
                context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
            }
            else
            {
                context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
            }

            context.RegisterCompilationStartAction(
                (CompilationStartAnalysisContext compilationContext) =>
            {
                Compilation compilation   = compilationContext.Compilation;
                var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilation);

                if (!wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName("System.Xml.Xsl.XsltSettings", out var type))
                {
                    return;
                }

                var configuration = Configuration.GetOrCreate(compilationContext);

                compilationContext.RegisterOperationBlockStartAction(
                    operationBlockStartContext =>
                {
                    ISymbol owningSymbol                = operationBlockStartContext.OwningSymbol;
                    AnalyzerOptions options             = operationBlockStartContext.Options;
                    CancellationToken cancellationToken = operationBlockStartContext.CancellationToken;
                    if (options.IsConfiguredToSkipAnalysis(Rule, owningSymbol, compilation, cancellationToken))
                    {
                        return;
                    }

                    bool?GetValue(IOperation operation, IOperation value, OperationAnalysisContext operationAnalysisContext)
                    {
                        if (value.ConstantValue.HasValue && value.ConstantValue.Value is bool isEnableScript)
                        {
                            return(isEnableScript);
                        }

                        if (!operation.TryGetEnclosingControlFlowGraph(out var cfg))
                        {
                            return(null);
                        }

                        var valueContentResult = ValueContentAnalysis.TryGetOrComputeResult(cfg, owningSymbol, wellKnownTypeProvider,
                                                                                            operationAnalysisContext.Options, Rule, PointsToAnalysisKind.Complete, operationAnalysisContext.CancellationToken);
                        if (valueContentResult == null)
                        {
                            return(null);
                        }

                        ValueContentAbstractValue abstractValue = valueContentResult[value.Kind, value.Syntax];

                        PropertySetAbstractValueKind kind = PropertySetCallbacks.EvaluateLiteralValues(abstractValue, (object?o) => o is true);
                        if (kind == PropertySetAbstractValueKind.MaybeFlagged || kind == PropertySetAbstractValueKind.Flagged)
                        {
                            return(true);
                        }

                        kind = PropertySetCallbacks.EvaluateLiteralValues(abstractValue, (object?o) => o is false);
                        if (kind == PropertySetAbstractValueKind.Flagged)
                        {
                            return(false);
                        }

                        return(null);
                    }

                    operationBlockStartContext.RegisterOperationAction(
                        ctx =>
                    {
                        IAssignmentOperation operation = (IAssignmentOperation)ctx.Operation;
                        if (!(operation.Target is IPropertyReferenceOperation propertyReferenceOperation))
                        {
                            return;
                        }

                        if (propertyReferenceOperation.Member.ContainingType != type)
                        {
                            return;
                        }

                        if (propertyReferenceOperation.Member.Name == "EnableScript")
                        {
                            var enableScript = GetValue(operation, operation.Value, ctx);
                            if ((enableScript.HasValue && enableScript.Value) ||
                                !enableScript.HasValue && configuration.AuditMode)
                            {
                                ctx.ReportDiagnostic(Diagnostic.Create(Rule, operation.Syntax.GetLocation()));
                            }
                        }
                    },
                        OperationKind.SimpleAssignment);

                    operationBlockStartContext.RegisterOperationAction(
                        ctx =>
                    {
                        var operation = (IPropertyReferenceOperation)ctx.Operation;
                        if (operation.Property.ContainingType != type || operation.Property.Name != "TrustedXslt")
                        {
                            return;
                        }

                        ctx.ReportDiagnostic(Diagnostic.Create(Rule, operation.Syntax.GetLocation()));
                    },
                        OperationKind.PropertyReference);

                    operationBlockStartContext.RegisterOperationAction(
                        ctx =>
                    {
                        IObjectCreationOperation invocationOperation = (IObjectCreationOperation)ctx.Operation;
                        if (invocationOperation.Constructor.ContainingType != type)
                        {
                            return;
                        }

                        var enableScriptArg = invocationOperation.Arguments.FirstOrDefault(x => x.Parameter.Name == "enableScript");
                        if (enableScriptArg == null)
                        {
                            return;
                        }

                        var enableScript = GetValue(invocationOperation, enableScriptArg.Value, ctx);
                        if ((enableScript.HasValue && enableScript.Value) ||
                            !enableScript.HasValue && configuration.AuditMode)
                        {
                            ctx.ReportDiagnostic(Diagnostic.Create(Rule, invocationOperation.Syntax.GetLocation()));
                        }
                    },
                        OperationKind.ObjectCreation);
                });
            });
        }