public override void Initialize(AnalysisContext context)
        {
            context.EnableConcurrentExecution();

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

            HazardousUsageEvaluatorCollection hazardousUsageEvaluators = new HazardousUsageEvaluatorCollection(
                new HazardousUsageEvaluator("GetBytes", HazardousUsageCallback));

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

                if (!wellKnownTypeProvider.TryGetTypeByMetadataName(WellKnownTypeNames.SystemSecurityCryptographyRfc2898DeriveBytes, out var rfc2898DeriveBytesTypeSymbol))
                {
                    return;
                }

                var cancellationToken        = compilationStartAnalysisContext.CancellationToken;
                var sufficientIterationCount = compilationStartAnalysisContext.Options.GetUnsignedIntegralOptionValue(
                    optionName: EditorConfigOptionNames.SufficientIterationCountForWeakKDFAlgorithm,
                    rule: DefinitelyUseWeakKDFInsufficientIterationCountRule,
                    defaultValue: 100000,
                    cancellationToken: cancellationToken);
                var constructorMapper = new ConstructorMapper(
                    (IMethodSymbol constructorMethod, IReadOnlyList <ValueContentAbstractValue> argumentValueContentAbstractValues,
                     IReadOnlyList <PointsToAbstractValue> argumentPointsToAbstractValues) =>
                {
                    var kind = DefaultIterationCount >= sufficientIterationCount ? PropertySetAbstractValueKind.Unflagged : PropertySetAbstractValueKind.Flagged;

                    if (constructorMethod.Parameters.Length >= 3)
                    {
                        if (constructorMethod.Parameters[2].Name == "iterations" &&
                            constructorMethod.Parameters[2].Type.SpecialType == SpecialType.System_Int32)
                        {
                            kind = PropertySetAnalysis.EvaluateLiteralValues(argumentValueContentAbstractValues[2], o => Convert.ToInt32(o) < sufficientIterationCount);
                        }
                    }

                    return(PropertySetAbstractValue.GetInstance(kind));
                });
                var propertyMappers = new PropertyMapperCollection(
                    new PropertyMapper(
                        "IterationCount",
                        (ValueContentAbstractValue valueContentAbstractValue) =>
                {
                    return(PropertySetAnalysis.EvaluateLiteralValues(valueContentAbstractValue, o => Convert.ToInt32(o) < sufficientIterationCount));
                }));
                var rootOperationsNeedingAnalysis = PooledHashSet <(IOperation, ISymbol)> .GetInstance();

                compilationStartAnalysisContext.RegisterOperationBlockStartAction(
                    (OperationBlockStartAnalysisContext operationBlockStartAnalysisContext) =>
                {
                    operationBlockStartAnalysisContext.RegisterOperationAction(
                        (OperationAnalysisContext operationAnalysisContext) =>
                    {
                        var invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation;

                        if (rfc2898DeriveBytesTypeSymbol.Equals(invocationOperation.Instance?.Type) &&
                            invocationOperation.TargetMethod.Name == "GetBytes")
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                rootOperationsNeedingAnalysis.Add((invocationOperation.GetRoot(), operationAnalysisContext.ContainingSymbol));
                            }
                        }
                    },
                        OperationKind.Invocation);

                    operationBlockStartAnalysisContext.RegisterOperationAction(
                        (OperationAnalysisContext operationAnalysisContext) =>
                    {
                        var argumentOperation = (IArgumentOperation)operationAnalysisContext.Operation;

                        if (rfc2898DeriveBytesTypeSymbol.Equals(argumentOperation.Parameter.Type))
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                rootOperationsNeedingAnalysis.Add((argumentOperation.GetRoot(), operationAnalysisContext.ContainingSymbol));
                            }
                        }
                    },
                        OperationKind.Argument);
                });

                compilationStartAnalysisContext.RegisterCompilationEndAction(
                    (CompilationAnalysisContext compilationAnalysisContext) =>
                {
                    PooledDictionary <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> allResults = null;

                    try
                    {
                        lock (rootOperationsNeedingAnalysis)
                        {
                            if (!rootOperationsNeedingAnalysis.Any())
                            {
                                return;
                            }

                            allResults = PropertySetAnalysis.BatchGetOrComputeHazardousUsages(
                                compilationAnalysisContext.Compilation,
                                rootOperationsNeedingAnalysis,
                                WellKnownTypeNames.SystemSecurityCryptographyRfc2898DeriveBytes,
                                constructorMapper,
                                propertyMappers,
                                hazardousUsageEvaluators,
                                InterproceduralAnalysisConfiguration.Create(
                                    compilationAnalysisContext.Options,
                                    SupportedDiagnostics,
                                    defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.ContextSensitive,
                                    cancellationToken: cancellationToken));
                        }

                        if (allResults == null)
                        {
                            return;
                        }

                        foreach (KeyValuePair <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> kvp
                                 in allResults)
                        {
                            DiagnosticDescriptor descriptor;
                            switch (kvp.Value)
                            {
                            case HazardousUsageEvaluationResult.Flagged:
                                descriptor = DefinitelyUseWeakKDFInsufficientIterationCountRule;
                                break;

                            case HazardousUsageEvaluationResult.MaybeFlagged:
                                descriptor = MaybeUseWeakKDFInsufficientIterationCountRule;
                                break;

                            default:
                                Debug.Fail($"Unhandled result value {kvp.Value}");
                                continue;
                            }

                            compilationAnalysisContext.ReportDiagnostic(
                                Diagnostic.Create(
                                    descriptor,
                                    kvp.Key.Location,
                                    sufficientIterationCount));
                        }
                    }
                    finally
                    {
                        rootOperationsNeedingAnalysis.Free();
                        allResults?.Free();
                    }
                });
            });
        }
        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 compilationStartAnalysisContext) =>
            {
                var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilationStartAnalysisContext.Compilation);

                if (!wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemSecurityCryptographySymmetricAlgorithm, out var symmetricAlgorithmTypeSymbol))
                {
                    return;
                }

                var rootOperationsNeedingAnalysis = PooledHashSet <(IOperation, ISymbol)> .GetInstance();

                compilationStartAnalysisContext.RegisterOperationBlockStartAction(
                    (OperationBlockStartAnalysisContext operationBlockStartAnalysisContext) =>
                {
                    var owningSymbol = operationBlockStartAnalysisContext.OwningSymbol;

                    // TODO: Handle case when exactly one of the below rules is configured to skip analysis.
                    if (operationBlockStartAnalysisContext.Options.IsConfiguredToSkipAnalysis(DefinitelyUseCreateEncryptorWithNonDefaultIVRule,
                                                                                              owningSymbol, operationBlockStartAnalysisContext.Compilation, operationBlockStartAnalysisContext.CancellationToken) &&
                        operationBlockStartAnalysisContext.Options.IsConfiguredToSkipAnalysis(MaybeUseCreateEncryptorWithNonDefaultIVRule,
                                                                                              owningSymbol, operationBlockStartAnalysisContext.Compilation, operationBlockStartAnalysisContext.CancellationToken))
                    {
                        return;
                    }

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

                        if (methodSymbol.ContainingType.GetBaseTypesAndThis().Contains(symmetricAlgorithmTypeSymbol) &&
                            methodSymbol.Name == "CreateEncryptor")
                        {
                            if (methodSymbol.Parameters.IsEmpty)
                            {
                                lock (rootOperationsNeedingAnalysis)
                                {
                                    rootOperationsNeedingAnalysis.Add((invocationOperation.GetRoot(), operationAnalysisContext.ContainingSymbol));
                                }
                            }
                            else
                            {
                                operationAnalysisContext.ReportDiagnostic(
                                    invocationOperation.CreateDiagnostic(
                                        DefinitelyUseCreateEncryptorWithNonDefaultIVRule));
                            }
                        }
                    },
                        OperationKind.Invocation);
                });

                compilationStartAnalysisContext.RegisterCompilationEndAction(
                    (CompilationAnalysisContext compilationAnalysisContext) =>
                {
                    PooledDictionary <(Location Location, IMethodSymbol?Method), HazardousUsageEvaluationResult>?allResults = null;

                    try
                    {
                        lock (rootOperationsNeedingAnalysis)
                        {
                            if (!rootOperationsNeedingAnalysis.Any())
                            {
                                return;
                            }

                            allResults = PropertySetAnalysis.BatchGetOrComputeHazardousUsages(
                                compilationAnalysisContext.Compilation,
                                rootOperationsNeedingAnalysis,
                                compilationAnalysisContext.Options,
                                WellKnownTypeNames.SystemSecurityCryptographySymmetricAlgorithm,
                                ConstructorMapper,
                                PropertyMappers,
                                HazardousUsageEvaluators,
                                InterproceduralAnalysisConfiguration.Create(
                                    compilationAnalysisContext.Options,
                                    SupportedDiagnostics,
                                    rootOperationsNeedingAnalysis.First().Item1.Syntax.SyntaxTree,
                                    compilationAnalysisContext.Compilation,
                                    defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.ContextSensitive,
                                    cancellationToken: compilationAnalysisContext.CancellationToken));
                        }

                        if (allResults == null)
                        {
                            return;
                        }

                        foreach (KeyValuePair <(Location Location, IMethodSymbol?Method), HazardousUsageEvaluationResult> kvp
                                 in allResults)
                        {
                            DiagnosticDescriptor descriptor;
                            switch (kvp.Value)
                            {
                            case HazardousUsageEvaluationResult.Flagged:
                                descriptor = DefinitelyUseCreateEncryptorWithNonDefaultIVRule;
                                break;

                            case HazardousUsageEvaluationResult.MaybeFlagged:
                                descriptor = MaybeUseCreateEncryptorWithNonDefaultIVRule;
                                break;

                            default:
                                Debug.Fail($"Unhandled result value {kvp.Value}");
                                continue;
                            }

                            RoslynDebug.Assert(kvp.Key.Method != null);            // HazardousUsageEvaluations only for invocations.
                            compilationAnalysisContext.ReportDiagnostic(
                                Diagnostic.Create(
                                    descriptor,
                                    kvp.Key.Location,
                                    kvp.Key.Method.ToDisplayString(
                                        SymbolDisplayFormat.MinimallyQualifiedFormat)));
                        }
                    }
                    finally
                    {
                        rootOperationsNeedingAnalysis.Free(compilationAnalysisContext.CancellationToken);
                        allResults?.Free(compilationAnalysisContext.CancellationToken);
                    }
                });
            });
        }
Exemplo n.º 3
0
        public override void Initialize(AnalysisContext context)
        {
            context.EnableConcurrentExecution();

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

            // If there are more classes implement IResponseCookies, add them here later.
            HazardousUsageEvaluatorCollection hazardousUsageEvaluators = new HazardousUsageEvaluatorCollection(
                new HazardousUsageEvaluator(
                    WellKnownTypeNames.MicrosoftAspNetCoreHttpInternalResponseCookies,
                    "Append",
                    "options",
                    HazardousUsageCallback));

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

                if (!wellKnownTypeProvider.TryGetTypeByMetadataName(
                        WellKnownTypeNames.MicrosoftAspNetCoreHttpIResponseCookies,
                        out var iResponseCookiesTypeSymbol))
                {
                    return;
                }

                wellKnownTypeProvider.TryGetTypeByMetadataName(
                    WellKnownTypeNames.MicrosoftAspNetCoreHttpCookieOptions,
                    out var cookieOptionsTypeSymbol);
                var rootOperationsNeedingAnalysis = PooledHashSet <(IOperation, ISymbol)> .GetInstance();

                compilationStartAnalysisContext.RegisterOperationBlockStartAction(
                    (OperationBlockStartAnalysisContext operationBlockStartAnalysisContext) =>
                {
                    operationBlockStartAnalysisContext.RegisterOperationAction(
                        (OperationAnalysisContext operationAnalysisContext) =>
                    {
                        var invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation;
                        var methodSymbol        = invocationOperation.TargetMethod;

                        if (methodSymbol.ContainingType is INamedTypeSymbol namedTypeSymbol &&
                            namedTypeSymbol.Interfaces.Contains(iResponseCookiesTypeSymbol) &&
                            invocationOperation.TargetMethod.Name == "Append")
                        {
                            if (methodSymbol.Parameters.Length < 3)
                            {
                                operationAnalysisContext.ReportDiagnostic(
                                    invocationOperation.CreateDiagnostic(
                                        DefinitelyUseSecureCookiesASPNetCoreRule));
                            }
                            else
                            {
                                lock (rootOperationsNeedingAnalysis)
                                {
                                    rootOperationsNeedingAnalysis.Add((invocationOperation.GetRoot(), operationAnalysisContext.ContainingSymbol));
                                }
                            }
                        }
                    },
                        OperationKind.Invocation);

                    operationBlockStartAnalysisContext.RegisterOperationAction(
                        (OperationAnalysisContext operationAnalysisContext) =>
                    {
                        var argumentOperation = (IArgumentOperation)operationAnalysisContext.Operation;

                        if (argumentOperation.Parameter.Type.Equals(cookieOptionsTypeSymbol))
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                rootOperationsNeedingAnalysis.Add((argumentOperation.GetRoot(), operationAnalysisContext.ContainingSymbol));
                            }
                        }
                    },
                        OperationKind.Argument);
                });

                compilationStartAnalysisContext.RegisterCompilationEndAction(
                    (CompilationAnalysisContext compilationAnalysisContext) =>
                {
                    PooledDictionary <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> allResults = null;

                    try
                    {
                        lock (rootOperationsNeedingAnalysis)
                        {
                            if (!rootOperationsNeedingAnalysis.Any())
                            {
                                return;
                            }

                            allResults = PropertySetAnalysis.BatchGetOrComputeHazardousUsages(
                                compilationAnalysisContext.Compilation,
                                rootOperationsNeedingAnalysis,
                                WellKnownTypeNames.MicrosoftAspNetCoreHttpCookieOptions,
                                constructorMapper,
                                PropertyMappers,
                                hazardousUsageEvaluators,
                                InterproceduralAnalysisConfiguration.Create(
                                    compilationAnalysisContext.Options,
                                    SupportedDiagnostics,
                                    defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.ContextSensitive,
                                    cancellationToken: compilationAnalysisContext.CancellationToken));
                        }

                        if (allResults == null)
                        {
                            return;
                        }

                        foreach (KeyValuePair <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> kvp
                                 in allResults)
                        {
                            DiagnosticDescriptor descriptor;
                            switch (kvp.Value)
                            {
                            case HazardousUsageEvaluationResult.Flagged:
                                descriptor = DefinitelyUseSecureCookiesASPNetCoreRule;
                                break;

                            case HazardousUsageEvaluationResult.MaybeFlagged:
                                descriptor = MaybeUseSecureCookiesASPNetCoreRule;
                                break;

                            default:
                                Debug.Fail($"Unhandled result value {kvp.Value}");
                                continue;
                            }

                            compilationAnalysisContext.ReportDiagnostic(
                                Diagnostic.Create(
                                    descriptor,
                                    kvp.Key.Location,
                                    kvp.Key.Method.ToDisplayString(
                                        SymbolDisplayFormat.MinimallyQualifiedFormat)));
                        }
                    }
                    finally
                    {
                        rootOperationsNeedingAnalysis.Free();
                        allResults?.Free();
                    }
                });
            });
        }
        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 compilationStartAnalysisContext) =>
            {
                if (!compilationStartAnalysisContext.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemWebHttpCookie,
                                                                                                  out INamedTypeSymbol? httpCookieSymbol))
                {
                    return;
                }

                PooledHashSet <(IOperation Operation, ISymbol ContainingSymbol)> rootOperationsNeedingAnalysis = PooledHashSet <(IOperation, ISymbol)> .GetInstance();

                compilationStartAnalysisContext.RegisterOperationBlockStartAction(
                    (OperationBlockStartAnalysisContext operationBlockStartAnalysisContext) =>
                {
                    ISymbol owningSymbol = operationBlockStartAnalysisContext.OwningSymbol;

                    if (owningSymbol.IsConfiguredToSkipAnalysis(
                            operationBlockStartAnalysisContext.Options,
                            Rule,
                            operationBlockStartAnalysisContext.Compilation,
                            operationBlockStartAnalysisContext.CancellationToken))
                    {
                        return;
                    }

                    operationBlockStartAnalysisContext.RegisterOperationAction(
                        (OperationAnalysisContext operationAnalysisContext) =>
                    {
                        ISimpleAssignmentOperation simpleAssignmentOperation =
                            (ISimpleAssignmentOperation)operationAnalysisContext.Operation;

                        if (simpleAssignmentOperation.Target is IPropertyReferenceOperation propertyReferenceOperation &&
                            httpCookieSymbol.Equals(propertyReferenceOperation.Property.ContainingType) &&
                            propertyReferenceOperation.Property.Name == "HttpOnly" &&
                            simpleAssignmentOperation.Value.ConstantValue.HasValue &&
                            simpleAssignmentOperation.Value.ConstantValue.Value.Equals(false))
                        {
                            operationAnalysisContext.ReportDiagnostic(
                                simpleAssignmentOperation.CreateDiagnostic(
                                    Rule));
                        }
                    },
                        OperationKind.SimpleAssignment);

                    operationBlockStartAnalysisContext.RegisterOperationAction(
                        (OperationAnalysisContext operationAnalysisContext) =>
                    {
                        IReturnOperation returnOperation = (IReturnOperation)operationAnalysisContext.Operation;

                        if (httpCookieSymbol.Equals(returnOperation.ReturnedValue?.Type))
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                rootOperationsNeedingAnalysis.Add(
                                    (returnOperation.GetRoot(), operationAnalysisContext.ContainingSymbol));
                            }
                        }
                    },
                        OperationKind.Return);

                    operationBlockStartAnalysisContext.RegisterOperationAction(
                        (OperationAnalysisContext operationAnalysisContext) =>
                    {
                        IArgumentOperation argumentOperation = (IArgumentOperation)operationAnalysisContext.Operation;

                        if (httpCookieSymbol.Equals(argumentOperation.Value.Type))
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                rootOperationsNeedingAnalysis.Add(
                                    (argumentOperation.GetRoot(), operationAnalysisContext.ContainingSymbol));
                            }
                        }
                    },
                        OperationKind.Argument);
                });

                compilationStartAnalysisContext.RegisterCompilationEndAction(
                    (CompilationAnalysisContext compilationAnalysisContext) =>
                {
                    PooledDictionary <(Location Location, IMethodSymbol?Method), HazardousUsageEvaluationResult>?allResults = null;

                    try
                    {
                        lock (rootOperationsNeedingAnalysis)
                        {
                            if (!rootOperationsNeedingAnalysis.Any())
                            {
                                return;
                            }

                            allResults = PropertySetAnalysis.BatchGetOrComputeHazardousUsages(
                                compilationAnalysisContext.Compilation,
                                rootOperationsNeedingAnalysis,
                                compilationAnalysisContext.Options,
                                WellKnownTypeNames.SystemWebHttpCookie,
                                ConstructorMapper,
                                PropertyMappers,
                                HazardousUsageEvaluators,
                                InterproceduralAnalysisConfiguration.Create(
                                    compilationAnalysisContext.Options,
                                    SupportedDiagnostics,
                                    defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.ContextSensitive,
                                    cancellationToken: compilationAnalysisContext.CancellationToken));
                        }

                        if (allResults == null)
                        {
                            return;
                        }

                        foreach (KeyValuePair <(Location Location, IMethodSymbol?Method), HazardousUsageEvaluationResult> kvp
                                 in allResults)
                        {
                            if (kvp.Value == HazardousUsageEvaluationResult.Flagged)
                            {
                                compilationAnalysisContext.ReportDiagnostic(
                                    Diagnostic.Create(
                                        Rule,
                                        kvp.Key.Location));
                            }
                        }
                    }
                    finally
                    {
                        rootOperationsNeedingAnalysis.Free();
                        allResults?.Free();
                    }
                });
            });
        }
        public sealed override void Initialize(AnalysisContext context)
        {
            ImmutableHashSet <string> cachedDeserializationMethodNames = this.DeserializationMethodNames;

            Debug.Assert(!string.IsNullOrWhiteSpace(this.DeserializerTypeMetadataName));
            Debug.Assert(!string.IsNullOrWhiteSpace(this.SerializationBinderPropertyMetadataName));
            Debug.Assert(!cachedDeserializationMethodNames.IsEmpty);
            Debug.Assert(this.BinderDefinitelyNotSetDescriptor != null);
            Debug.Assert(this.BinderMaybeNotSetDescriptor != null);

            context.EnableConcurrentExecution();

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

            // For PropertySetAnalysis dataflow analysis.
            PropertyMapperCollection propertyMappers = new PropertyMapperCollection(
                new PropertyMapper(
                    this.SerializationBinderPropertyMetadataName,
                    PropertySetCallbacks.FlagIfNull));

            HazardousUsageEvaluatorCollection hazardousUsageEvaluators =
                new HazardousUsageEvaluatorCollection(
                    cachedDeserializationMethodNames.Select(
                        methodName => new HazardousUsageEvaluator(
                            methodName,
                            PropertySetCallbacks.HazardousIfAllFlaggedOrAllUnknown)));

            context.RegisterCompilationStartAction(
                (CompilationStartAnalysisContext compilationStartAnalysisContext) =>
            {
                if (!compilationStartAnalysisContext.Compilation.TryGetOrCreateTypeByMetadataName(
                        this.DeserializerTypeMetadataName,
                        out INamedTypeSymbol? deserializerTypeSymbol))
                {
                    return;
                }

                PooledHashSet <(IOperation Operation, ISymbol ContainingSymbol)> rootOperationsNeedingAnalysis = PooledHashSet <(IOperation, ISymbol)> .GetInstance();

                compilationStartAnalysisContext.RegisterOperationBlockStartAction(
                    (OperationBlockStartAnalysisContext operationBlockStartAnalysisContext) =>
                {
                    var owningSymbol = operationBlockStartAnalysisContext.OwningSymbol;

                    // TODO: Handle case when exactly one of the below rules is configured to skip analysis.
                    if (owningSymbol.IsConfiguredToSkipAnalysis(operationBlockStartAnalysisContext.Options,
                                                                BinderDefinitelyNotSetDescriptor !, operationBlockStartAnalysisContext.Compilation, operationBlockStartAnalysisContext.CancellationToken) &&
                        owningSymbol.IsConfiguredToSkipAnalysis(operationBlockStartAnalysisContext.Options,
                                                                BinderMaybeNotSetDescriptor !, operationBlockStartAnalysisContext.Compilation, operationBlockStartAnalysisContext.CancellationToken))
                    {
                        return;
                    }

                    operationBlockStartAnalysisContext.RegisterOperationAction(
                        (OperationAnalysisContext operationAnalysisContext) =>
                    {
                        IObjectCreationOperation creationOperation =
                            (IObjectCreationOperation)operationAnalysisContext.Operation;
                        if (deserializerTypeSymbol.Equals(creationOperation.Type))
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                rootOperationsNeedingAnalysis.Add((operationAnalysisContext.Operation.GetRoot(), operationAnalysisContext.ContainingSymbol));
                            }
                        }
                    },
                        OperationKind.ObjectCreation);

                    operationBlockStartAnalysisContext.RegisterOperationAction(
                        (OperationAnalysisContext operationAnalysisContext) =>
                    {
                        IInvocationOperation invocationOperation =
                            (IInvocationOperation)operationAnalysisContext.Operation;
                        if (Equals(invocationOperation.Instance?.Type, deserializerTypeSymbol) &&
                            cachedDeserializationMethodNames.Contains(invocationOperation.TargetMethod.Name))
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                rootOperationsNeedingAnalysis.Add((operationAnalysisContext.Operation.GetRoot(), operationAnalysisContext.ContainingSymbol));
                            }
                        }
                    },
                        OperationKind.Invocation);

                    operationBlockStartAnalysisContext.RegisterOperationAction(
                        (OperationAnalysisContext operationAnalysisContext) =>
                    {
                        IMethodReferenceOperation methodReferenceOperation =
                            (IMethodReferenceOperation)operationAnalysisContext.Operation;
                        if (Equals(methodReferenceOperation.Instance?.Type, deserializerTypeSymbol) &&
                            cachedDeserializationMethodNames.Contains(
                                methodReferenceOperation.Method.MetadataName))
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                rootOperationsNeedingAnalysis.Add((operationAnalysisContext.Operation.GetRoot(), operationAnalysisContext.ContainingSymbol));
                            }
                        }
                    },
                        OperationKind.MethodReference);
                });

                compilationStartAnalysisContext.RegisterCompilationEndAction(
                    (CompilationAnalysisContext compilationAnalysisContext) =>
                {
                    PooledDictionary <(Location Location, IMethodSymbol?Method), HazardousUsageEvaluationResult>?allResults = null;
                    try
                    {
                        lock (rootOperationsNeedingAnalysis)
                        {
                            if (!rootOperationsNeedingAnalysis.Any())
                            {
                                return;
                            }

                            allResults = PropertySetAnalysis.BatchGetOrComputeHazardousUsages(
                                compilationAnalysisContext.Compilation,
                                rootOperationsNeedingAnalysis,
                                compilationAnalysisContext.Options,
                                this.DeserializerTypeMetadataName,
                                DoNotUseInsecureDeserializerWithoutBinderBase.ConstructorMapper,
                                propertyMappers,
                                hazardousUsageEvaluators,
                                InterproceduralAnalysisConfiguration.Create(
                                    compilationAnalysisContext.Options,
                                    SupportedDiagnostics,
                                    rootOperationsNeedingAnalysis.First().Operation.Syntax.SyntaxTree,
                                    compilationAnalysisContext.Compilation,
                                    defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.ContextSensitive,
                                    cancellationToken: compilationAnalysisContext.CancellationToken));
                        }

                        if (allResults == null)
                        {
                            return;
                        }

                        foreach (KeyValuePair <(Location Location, IMethodSymbol?Method), HazardousUsageEvaluationResult> kvp
                                 in allResults)
                        {
                            DiagnosticDescriptor descriptor;
                            switch (kvp.Value)
                            {
                            case HazardousUsageEvaluationResult.Flagged:
                                descriptor = this.BinderDefinitelyNotSetDescriptor !;
                                break;

                            case HazardousUsageEvaluationResult.MaybeFlagged:
                                descriptor = this.BinderMaybeNotSetDescriptor !;
                                break;

                            default:
                                Debug.Fail($"Unhandled result value {kvp.Value}");
                                continue;
                            }

                            RoslynDebug.Assert(kvp.Key.Method != null);            // HazardousUsageEvaluations only for invocations.
                            compilationAnalysisContext.ReportDiagnostic(
                                Diagnostic.Create(
                                    descriptor,
                                    kvp.Key.Location,
                                    kvp.Key.Method.ToDisplayString(
                                        SymbolDisplayFormat.MinimallyQualifiedFormat)));
                        }
                    }
                    finally
                    {
                        rootOperationsNeedingAnalysis.Free(compilationAnalysisContext.CancellationToken);
                        allResults?.Free(compilationAnalysisContext.CancellationToken);
                    }
                });
            });
        }
        public override void Initialize(AnalysisContext context)
        {
            context.EnableConcurrentExecution();

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

            HazardousUsageEvaluatorCollection hazardousUsageEvaluators = new HazardousUsageEvaluatorCollection(
                SecurityHelpers.JavaScriptSerializerDeserializationMethods.Select(
                    (string methodName) => new HazardousUsageEvaluator(methodName, HazardousUsageCallback)));

            context.RegisterCompilationStartAction(
                (CompilationStartAnalysisContext compilationStartAnalysisContext) =>
            {
                WellKnownTypeProvider wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilationStartAnalysisContext.Compilation);
                if (!wellKnownTypeProvider.TryGetTypeByMetadataName(WellKnownTypeNames.SystemWebScriptSerializationJavaScriptSerializer, out INamedTypeSymbol javaScriptSerializerSymbol) ||
                    !wellKnownTypeProvider.TryGetTypeByMetadataName(WellKnownTypeNames.SystemWebScriptSerializationJavaScriptTypeResolver, out INamedTypeSymbol javaScriptTypeResolverSymbol) ||
                    !wellKnownTypeProvider.TryGetTypeByMetadataName(WellKnownTypeNames.SystemWebScriptSerializationSimpleTypeResolver, out INamedTypeSymbol simpleTypeResolverSymbol))
                {
                    return;
                }

                // If JavaScriptSerializer is initialized with a SimpleTypeResolver, then that instance is flagged.
                ConstructorMapper constructorMapper = new ConstructorMapper(
                    (IMethodSymbol constructorMethod, IReadOnlyList <PointsToAbstractValue> argumentPointsToAbstractValues) =>
                {
                    PropertySetAbstractValueKind kind;
                    if (constructorMethod.Parameters.Length == 0)
                    {
                        kind = PropertySetAbstractValueKind.Unflagged;
                    }
                    else if (constructorMethod.Parameters.Length == 1 &&
                             javaScriptTypeResolverSymbol.Equals(constructorMethod.Parameters[0].Type))
                    {
                        PointsToAbstractValue pointsTo = argumentPointsToAbstractValues[0];
                        switch (pointsTo.Kind)
                        {
                        case PointsToAbstractValueKind.Invalid:
                        case PointsToAbstractValueKind.UnknownNull:
                        case PointsToAbstractValueKind.Undefined:
                            kind = PropertySetAbstractValueKind.Unflagged;
                            break;

                        case PointsToAbstractValueKind.KnownLocations:
                            if (pointsTo.Locations.Any(l => !l.IsNull && simpleTypeResolverSymbol.Equals(l.LocationTypeOpt)))
                            {
                                kind = PropertySetAbstractValueKind.Flagged;
                            }
                            else if (pointsTo.Locations.Any(l =>
                                                            !l.IsNull &&
                                                            javaScriptTypeResolverSymbol.Equals(l.LocationTypeOpt) &&
                                                            (l.CreationOpt == null || l.CreationOpt.Kind != OperationKind.ObjectCreation)))
                            {
                                // Points to a JavaScriptTypeResolver, but we don't know if the instance is a SimpleTypeResolver.
                                kind = PropertySetAbstractValueKind.MaybeFlagged;
                            }
                            else
                            {
                                kind = PropertySetAbstractValueKind.Unflagged;
                            }

                            break;

                        case PointsToAbstractValueKind.UnknownNotNull:
                        case PointsToAbstractValueKind.Unknown:
                            kind = PropertySetAbstractValueKind.MaybeFlagged;
                            break;

                        default:
                            Debug.Fail($"Unhandled PointsToAbstractValueKind {pointsTo.Kind}");
                            kind = PropertySetAbstractValueKind.Unflagged;
                            break;
                        }
                    }
                    else
                    {
                        Debug.Fail($"Unhandled JavaScriptSerializer constructor {constructorMethod.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat)}");
                        kind = PropertySetAbstractValueKind.Unflagged;
                    }

                    return(PropertySetAbstractValue.GetInstance(kind));
                });

                PooledHashSet <(IOperation Operation, ISymbol ContainingSymbol)> rootOperationsNeedingAnalysis = PooledHashSet <(IOperation, ISymbol)> .GetInstance();

                compilationStartAnalysisContext.RegisterOperationBlockStartAction(
                    (OperationBlockStartAnalysisContext operationBlockStartAnalysisContext) =>
                {
                    operationBlockStartAnalysisContext.RegisterOperationAction(
                        (OperationAnalysisContext operationAnalysisContext) =>
                    {
                        IInvocationOperation invocationOperation =
                            (IInvocationOperation)operationAnalysisContext.Operation;
                        if ((javaScriptSerializerSymbol.Equals(invocationOperation.Instance?.Type) &&
                             SecurityHelpers.JavaScriptSerializerDeserializationMethods.Contains(invocationOperation.TargetMethod.Name)) ||
                            simpleTypeResolverSymbol.Equals(invocationOperation.TargetMethod.ReturnType) ||
                            javaScriptTypeResolverSymbol.Equals(invocationOperation.TargetMethod.ReturnType))
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                rootOperationsNeedingAnalysis.Add((invocationOperation.GetRoot(), operationAnalysisContext.ContainingSymbol));
                            }
                        }
                    },
                        OperationKind.Invocation);

                    operationBlockStartAnalysisContext.RegisterOperationAction(
                        (OperationAnalysisContext operationAnalysisContext) =>
                    {
                        IMethodReferenceOperation methodReferenceOperation =
                            (IMethodReferenceOperation)operationAnalysisContext.Operation;
                        if (javaScriptSerializerSymbol.Equals(methodReferenceOperation.Instance?.Type) &&
                            SecurityHelpers.JavaScriptSerializerDeserializationMethods.Contains(methodReferenceOperation.Method.Name))
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                rootOperationsNeedingAnalysis.Add((operationAnalysisContext.Operation.GetRoot(), operationAnalysisContext.ContainingSymbol));
                            }
                        }
                    },
                        OperationKind.MethodReference);
                });

                compilationStartAnalysisContext.RegisterCompilationEndAction(
                    (CompilationAnalysisContext compilationAnalysisContext) =>
                {
                    PooledDictionary <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> allResults = null;
                    try
                    {
                        lock (rootOperationsNeedingAnalysis)
                        {
                            if (!rootOperationsNeedingAnalysis.Any())
                            {
                                return;
                            }

                            allResults = PropertySetAnalysis.BatchGetOrComputeHazardousUsages(
                                compilationAnalysisContext.Compilation,
                                rootOperationsNeedingAnalysis,
                                WellKnownTypeNames.SystemWebScriptSerializationJavaScriptSerializer,
                                constructorMapper,
                                PropertyMappers,
                                hazardousUsageEvaluators,
                                InterproceduralAnalysisConfiguration.Create(
                                    compilationAnalysisContext.Options,
                                    SupportedDiagnostics,
                                    defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.ContextSensitive,
                                    cancellationToken: compilationAnalysisContext.CancellationToken));
                        }

                        if (allResults == null)
                        {
                            return;
                        }

                        foreach (KeyValuePair <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> kvp
                                 in allResults)
                        {
                            DiagnosticDescriptor descriptor;
                            switch (kvp.Value)
                            {
                            case HazardousUsageEvaluationResult.Flagged:
                                descriptor = DefinitelyWithSimpleTypeResolver;
                                break;

                            case HazardousUsageEvaluationResult.MaybeFlagged:
                                descriptor = MaybeWithSimpleTypeResolver;
                                break;

                            default:
                                Debug.Fail($"Unhandled result value {kvp.Value}");
                                continue;
                            }

                            compilationAnalysisContext.ReportDiagnostic(
                                Diagnostic.Create(
                                    descriptor,
                                    kvp.Key.Location,
                                    kvp.Key.Method.ToDisplayString(
                                        SymbolDisplayFormat.MinimallyQualifiedFormat)));
                        }
                    }
                    finally
                    {
                        rootOperationsNeedingAnalysis.Free();
                        allResults?.Free();
                    }
                });
            });
        }
        public sealed override void Initialize(AnalysisContext context)
        {
            ImmutableHashSet <string> cachedDeserializationMethodNames = this.DeserializationMethodNames;

            Debug.Assert(!String.IsNullOrWhiteSpace(this.DeserializerTypeMetadataName));
            Debug.Assert(!String.IsNullOrWhiteSpace(this.SerializationBinderPropertyMetadataName));
            Debug.Assert(cachedDeserializationMethodNames != null);
            Debug.Assert(!cachedDeserializationMethodNames.IsEmpty);
            Debug.Assert(this.BinderDefinitelyNotSetDescriptor != null);
            Debug.Assert(this.BinderMaybeNotSetDescriptor != null);

            context.EnableConcurrentExecution();

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

            // For PropertySetAnalysis dataflow analysis.
            PropertyMapperCollection propertyMappers = new PropertyMapperCollection(
                new PropertyMapper(
                    this.SerializationBinderPropertyMetadataName,
                    (PointsToAbstractValue pointsToAbstractValue) =>
            {
                // A null SerializationBinder is what we want to flag as hazardous.
                switch (pointsToAbstractValue.NullState)
                {
                case NullAbstractValue.Null:
                    return(PropertySetAbstractValueKind.Flagged);

                case NullAbstractValue.NotNull:
                    return(PropertySetAbstractValueKind.Unflagged);

                default:
                    return(PropertySetAbstractValueKind.MaybeFlagged);
                }
            }));

            HazardousUsageEvaluatorCollection hazardousUsageEvaluators =
                new HazardousUsageEvaluatorCollection(
                    cachedDeserializationMethodNames.Select(
                        methodName => new HazardousUsageEvaluator(methodName, DoNotUseInsecureDeserializerWithoutBinderBase.HazardousIfNull)));

            context.RegisterCompilationStartAction(
                (CompilationStartAnalysisContext compilationStartAnalysisContext) =>
            {
                WellKnownTypeProvider wellKnownTypeProvider =
                    WellKnownTypeProvider.GetOrCreate(compilationStartAnalysisContext.Compilation);

                if (!wellKnownTypeProvider.TryGetTypeByMetadataName(
                        this.DeserializerTypeMetadataName,
                        out INamedTypeSymbol deserializerTypeSymbol))
                {
                    return;
                }

                PooledHashSet <(IOperation Operation, ISymbol ContainingSymbol)> rootOperationsNeedingAnalysis = PooledHashSet <(IOperation, ISymbol)> .GetInstance();

                compilationStartAnalysisContext.RegisterOperationBlockStartAction(
                    (OperationBlockStartAnalysisContext operationBlockStartAnalysisContext) =>
                {
                    operationBlockStartAnalysisContext.RegisterOperationAction(
                        (OperationAnalysisContext operationAnalysisContext) =>
                    {
                        IObjectCreationOperation creationOperation =
                            (IObjectCreationOperation)operationAnalysisContext.Operation;
                        if (deserializerTypeSymbol.Equals(creationOperation.Type))
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                rootOperationsNeedingAnalysis.Add((operationAnalysisContext.Operation.GetRoot(), operationAnalysisContext.ContainingSymbol));
                            }
                        }
                    },
                        OperationKind.ObjectCreation);

                    operationBlockStartAnalysisContext.RegisterOperationAction(
                        (OperationAnalysisContext operationAnalysisContext) =>
                    {
                        IInvocationOperation invocationOperation =
                            (IInvocationOperation)operationAnalysisContext.Operation;
                        if (Equals(invocationOperation.Instance?.Type, deserializerTypeSymbol) &&
                            cachedDeserializationMethodNames.Contains(invocationOperation.TargetMethod.Name))
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                rootOperationsNeedingAnalysis.Add((operationAnalysisContext.Operation.GetRoot(), operationAnalysisContext.ContainingSymbol));
                            }
                        }
                    },
                        OperationKind.Invocation);

                    operationBlockStartAnalysisContext.RegisterOperationAction(
                        (OperationAnalysisContext operationAnalysisContext) =>
                    {
                        IMethodReferenceOperation methodReferenceOperation =
                            (IMethodReferenceOperation)operationAnalysisContext.Operation;
                        if (Equals(methodReferenceOperation.Instance?.Type, deserializerTypeSymbol) &&
                            cachedDeserializationMethodNames.Contains(
                                methodReferenceOperation.Method.MetadataName))
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                rootOperationsNeedingAnalysis.Add((operationAnalysisContext.Operation.GetRoot(), operationAnalysisContext.ContainingSymbol));
                            }
                        }
                    },
                        OperationKind.MethodReference);
                });

                compilationStartAnalysisContext.RegisterCompilationEndAction(
                    (CompilationAnalysisContext compilationAnalysisContext) =>
                {
                    PooledDictionary <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> allResults = null;
                    try
                    {
                        lock (rootOperationsNeedingAnalysis)
                        {
                            if (!rootOperationsNeedingAnalysis.Any())
                            {
                                return;
                            }

                            allResults = PropertySetAnalysis.BatchGetOrComputeHazardousUsages(
                                compilationAnalysisContext.Compilation,
                                rootOperationsNeedingAnalysis,
                                this.DeserializerTypeMetadataName,
                                DoNotUseInsecureDeserializerWithoutBinderBase.ConstructorMapper,
                                propertyMappers,
                                hazardousUsageEvaluators,
                                InterproceduralAnalysisConfiguration.Create(
                                    compilationAnalysisContext.Options,
                                    SupportedDiagnostics,
                                    defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.ContextSensitive,
                                    cancellationToken: compilationAnalysisContext.CancellationToken));
                        }

                        if (allResults == null)
                        {
                            return;
                        }

                        foreach (KeyValuePair <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> kvp
                                 in allResults)
                        {
                            DiagnosticDescriptor descriptor;
                            switch (kvp.Value)
                            {
                            case HazardousUsageEvaluationResult.Flagged:
                                descriptor = this.BinderDefinitelyNotSetDescriptor;
                                break;

                            case HazardousUsageEvaluationResult.MaybeFlagged:
                                descriptor = this.BinderMaybeNotSetDescriptor;
                                break;

                            default:
                                Debug.Fail($"Unhandled result value {kvp.Value}");
                                continue;
                            }

                            compilationAnalysisContext.ReportDiagnostic(
                                Diagnostic.Create(
                                    descriptor,
                                    kvp.Key.Location,
                                    kvp.Key.Method.ToDisplayString(
                                        SymbolDisplayFormat.MinimallyQualifiedFormat)));
                        }
                    }
                    finally
                    {
                        rootOperationsNeedingAnalysis.Free();
                        allResults?.Free();
                    }
                });
            });
        }
Exemplo n.º 8
0
        public override void Initialize(AnalysisContext context)
        {
            context.EnableConcurrentExecution();

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

            HazardousUsageEvaluatorCollection hazardousUsageEvaluators = new HazardousUsageEvaluatorCollection(
                new HazardousUsageEvaluator("Add", HazardousUsageCallback));

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

                if (!wellKnownTypeProvider.TryGetTypeByMetadataName(WellKnownTypeNames.SystemSecurityCryptographyX509CertificatesX509Store, out var x509TypeSymbol))
                {
                    return;
                }

                if (!wellKnownTypeProvider.TryGetTypeByMetadataName(WellKnownTypeNames.SystemSecurityCryptographyX509CertificatesStoreName, out var storeNameTypeSymbol))
                {
                    return;
                }

                // If X509Store is initialized with Root store, then that instance is flagged.
                var constructorMapper = new ConstructorMapper(
                    (IMethodSymbol constructorMethod, IReadOnlyList <ValueContentAbstractValue> argumentValueContentAbstractValues,
                     IReadOnlyList <PointsToAbstractValue> argumentPointsToAbstractValues) =>
                {
                    var kind = PropertySetAbstractValueKind.Unflagged;

                    if (constructorMethod.Parameters.Length > 0)
                    {
                        if (constructorMethod.Parameters[0].Type.Equals(storeNameTypeSymbol))
                        {
                            kind = PropertySetCallbacks.EvaluateLiteralValues(argumentValueContentAbstractValues[0], o => o.Equals(6));
                        }
                        else if (constructorMethod.Parameters[0].Type.SpecialType == SpecialType.System_String)
                        {
                            kind = PropertySetCallbacks.EvaluateLiteralValues(
                                argumentValueContentAbstractValues[0],
                                s => string.Equals(s.ToString(), "root", StringComparison.OrdinalIgnoreCase));
                        }
                    }

                    return(PropertySetAbstractValue.GetInstance(kind));
                });

                var rootOperationsNeedingAnalysis = PooledHashSet <(IOperation, ISymbol)> .GetInstance();

                compilationStartAnalysisContext.RegisterOperationBlockStartAction(
                    (OperationBlockStartAnalysisContext operationBlockStartAnalysisContext) =>
                {
                    operationBlockStartAnalysisContext.RegisterOperationAction(
                        (OperationAnalysisContext operationAnalysisContext) =>
                    {
                        var invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation;

                        if (x509TypeSymbol.Equals(invocationOperation.Instance?.Type) &&
                            invocationOperation.TargetMethod.Name == "Add")
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                rootOperationsNeedingAnalysis.Add((invocationOperation.GetRoot(), operationAnalysisContext.ContainingSymbol));
                            }
                        }
                    },
                        OperationKind.Invocation);

                    operationBlockStartAnalysisContext.RegisterOperationAction(
                        (OperationAnalysisContext operationAnalysisContext) =>
                    {
                        var argumentOperation = (IArgumentOperation)operationAnalysisContext.Operation;

                        if (x509TypeSymbol.Equals(argumentOperation.Parameter.Type))
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                rootOperationsNeedingAnalysis.Add((argumentOperation.GetRoot(), operationAnalysisContext.ContainingSymbol));
                            }
                        }
                    },
                        OperationKind.Argument);
                });

                compilationStartAnalysisContext.RegisterCompilationEndAction(
                    (CompilationAnalysisContext compilationAnalysisContext) =>
                {
                    PooledDictionary <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> allResults = null;

                    try
                    {
                        lock (rootOperationsNeedingAnalysis)
                        {
                            if (!rootOperationsNeedingAnalysis.Any())
                            {
                                return;
                            }

                            allResults = PropertySetAnalysis.BatchGetOrComputeHazardousUsages(
                                compilationAnalysisContext.Compilation,
                                rootOperationsNeedingAnalysis,
                                WellKnownTypeNames.SystemSecurityCryptographyX509CertificatesX509Store,
                                constructorMapper,
                                PropertyMappers,
                                hazardousUsageEvaluators,
                                InterproceduralAnalysisConfiguration.Create(
                                    compilationAnalysisContext.Options,
                                    SupportedDiagnostics,
                                    defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.ContextSensitive,
                                    cancellationToken: compilationAnalysisContext.CancellationToken));
                        }

                        if (allResults == null)
                        {
                            return;
                        }

                        foreach (KeyValuePair <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> kvp
                                 in allResults)
                        {
                            DiagnosticDescriptor descriptor;
                            switch (kvp.Value)
                            {
                            case HazardousUsageEvaluationResult.Flagged:
                                descriptor = DefinitelyInstallRootCertRule;
                                break;

                            case HazardousUsageEvaluationResult.MaybeFlagged:
                                descriptor = MaybeInstallRootCertRule;
                                break;

                            default:
                                Debug.Fail($"Unhandled result value {kvp.Value}");
                                continue;
                            }

                            compilationAnalysisContext.ReportDiagnostic(
                                Diagnostic.Create(
                                    descriptor,
                                    kvp.Key.Location,
                                    kvp.Key.Method.ToDisplayString(
                                        SymbolDisplayFormat.MinimallyQualifiedFormat)));
                        }
                    }
                    finally
                    {
                        rootOperationsNeedingAnalysis.Free();
                        allResults?.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 compilationStartAnalysisContext) =>
            {
                Compilation compilation   = compilationStartAnalysisContext.Compilation;
                var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilation);

                if (!wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName(ValidatorTypeName, out var validatorType))
                {
                    return;
                }

                var rootOperationsNeedingAnalysis = PooledHashSet <(IOperation, ISymbol)> .GetInstance();

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

                    operationBlockStartContext.RegisterOperationAction(
                        (OperationAnalysisContext operationAnalysisContext) =>
                    {
                        var returnOperation = (IReturnOperation)operationAnalysisContext.Operation;

                        if (validatorType.Equals(returnOperation.ReturnedValue?.Type))
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                rootOperationsNeedingAnalysis.Add(
                                    (returnOperation.GetRoot(), operationAnalysisContext.ContainingSymbol));
                            }
                        }
                    },
                        OperationKind.Return);

                    operationBlockStartContext.RegisterOperationAction(
                        (OperationAnalysisContext operationAnalysisContext) =>
                    {
                        var argumentOperation = (IArgumentOperation)operationAnalysisContext.Operation;

                        if (argumentOperation.Parameter.Type.Equals(validatorType))
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                rootOperationsNeedingAnalysis.Add((argumentOperation.GetRoot(), operationAnalysisContext.ContainingSymbol));
                            }
                        }
                    },
                        OperationKind.Argument);

                    operationBlockStartContext.RegisterOperationAction(
                        ctx =>
                    {
                        var operation = (IObjectCreationOperation)ctx.Operation;
                        if (validatorType.Equals(operation.Type))
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                rootOperationsNeedingAnalysis.Add((operation.GetRoot(), ctx.ContainingSymbol));
                            }
                        }
                    },
                        OperationKind.ObjectCreation);
                });

                compilationStartAnalysisContext.RegisterCompilationEndAction(
                    (CompilationAnalysisContext compilationAnalysisContext) =>
                {
                    PooledDictionary <(Location Location, IMethodSymbol?Method), HazardousUsageEvaluationResult>?allResults = null;

                    try
                    {
                        lock (rootOperationsNeedingAnalysis)
                        {
                            if (!rootOperationsNeedingAnalysis.Any())
                            {
                                return;
                            }

                            PooledDictionary <(Location Location, IMethodSymbol?Method), HazardousUsageEvaluationResult>?GetHazardousUsages(
                                ConstructorMapper constructorMapper,
                                PropertyMapperCollection propertyMappers,
                                HazardousUsageEvaluatorCollection hazardousUsageEvaluators)
                            {
                                return(PropertySetAnalysis.BatchGetOrComputeHazardousUsages(
                                           compilationAnalysisContext.Compilation,
                                           rootOperationsNeedingAnalysis,
                                           compilationAnalysisContext.Options,
                                           ValidatorTypeName,
                                           constructorMapper,
                                           propertyMappers,
                                           hazardousUsageEvaluators,
                                           InterproceduralAnalysisConfiguration.Create(
                                               compilationAnalysisContext.Options,
                                               SupportedDiagnostics,
                                               rootOperationsNeedingAnalysis.First().Item1,
                                               compilationAnalysisContext.Compilation,
                                               defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.ContextSensitive,
                                               cancellationToken: compilationAnalysisContext.CancellationToken)));
                            }

                            var configuration = Configuration.GetOrCreate(compilationStartAnalysisContext);

                            foreach (var requiredProperty in configuration.PasswordValidatorRequiredProperties)
                            {
                                allResults?.Free(compilationAnalysisContext.CancellationToken);
                                allResults = null;
                                (PropertyMapperCollection propertyMappers, ConstructorMapper constructorMapper) =
                                    BuildRequiredPropertiesMappers((x) => PropertySetToTrueCallback(x, configuration.AuditMode), requiredProperty);
                                allResults = GetHazardousUsages(constructorMapper, propertyMappers, HazardousUsageEvaluators);
                                ReportDiagnostics(
                                    RuleRequiredPasswordValidators,
                                    compilationAnalysisContext,
                                    allResults,
                                    configuration.AuditMode,
                                    requiredProperty);
                            }

                            allResults?.Free(compilationAnalysisContext.CancellationToken);
                            allResults = null;
                            (PropertyMapperCollection propertyMappers2, ConstructorMapper constructorMapper2) =
                                BuildRequiredPropertiesMappers((x) => PropertyLenCallback(x, configuration.AuditMode, configuration.PasswordValidatorRequiredLength), "RequiredLength");
                            allResults = GetHazardousUsages(constructorMapper2, propertyMappers2, HazardousUsageEvaluators);
                            ReportDiagnostics(
                                RulePasswordLength,
                                compilationAnalysisContext,
                                allResults,
                                configuration.AuditMode,
                                configuration.PasswordValidatorRequiredLength);

                            var hazardousUsageEvaluators = new HazardousUsageEvaluatorCollection(
                                new HazardousUsageEvaluator(
                                    HazardousUsageEvaluatorKind.Return,
                                    (abstractValue) => PropertiesCountEvaluatorCallback(
                                        abstractValue, configuration.MinimumPasswordValidatorProperties, configuration.AuditMode)),
                                new HazardousUsageEvaluator(
                                    HazardousUsageEvaluatorKind.Initialization,
                                    (abstractValue) => PropertiesCountEvaluatorCallback(
                                        abstractValue, configuration.MinimumPasswordValidatorProperties, configuration.AuditMode)),
                                new HazardousUsageEvaluator(
                                    HazardousUsageEvaluatorKind.Argument,
                                    (abstractValue) => PropertiesCountEvaluatorCallback(
                                        abstractValue, configuration.MinimumPasswordValidatorProperties, configuration.AuditMode)));
                            allResults?.Free(compilationAnalysisContext.CancellationToken);
                            allResults = null;
                            (PropertyMapperCollection propertyMappers3, ConstructorMapper constructorMapper3) =
                                BuildRequiredPropertiesMappers((x) => PropertySetToTrueCallback(x, configuration.AuditMode), AllPropertyNames);
                            allResults = GetHazardousUsages(constructorMapper3, propertyMappers3, hazardousUsageEvaluators);
                            ReportDiagnostics(
                                RulePasswordValidators,
                                compilationAnalysisContext,
                                allResults,
                                configuration.AuditMode,
                                configuration.MinimumPasswordValidatorProperties);
                        }
                    }
                    finally
                    {
                        rootOperationsNeedingAnalysis.Free(compilationAnalysisContext.CancellationToken);
                        allResults?.Free(compilationAnalysisContext.CancellationToken);
                    }
                });
            });
        }