Example #1
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 compilation           = compilationStartAnalysisContext.Compilation;
                var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilation);

                if (!wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemRuntimeInteropServicesDllImportAttribute, out INamedTypeSymbol? dllImportAttributeTypeSymbol) ||
                    !wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemRuntimeInteropServicesDefaultDllImportSearchPathsAttribute, out INamedTypeSymbol? defaultDllImportSearchPathsAttributeTypeSymbol))
                {
                    return;
                }

                var cancellationToken             = compilationStartAnalysisContext.CancellationToken;
                var unsafeDllImportSearchPathBits = compilationStartAnalysisContext.Options.GetUnsignedIntegralOptionValue(
                    optionName: EditorConfigOptionNames.UnsafeDllImportSearchPathBits,
                    rule: DoNotUseUnsafeDllImportSearchPathRule,
                    defaultValue: UnsafeBits,
                    cancellationToken: cancellationToken);
                var defaultDllImportSearchPathsAttributeOnAssembly = compilation.Assembly.GetAttributes().FirstOrDefault(o => o.AttributeClass.Equals(defaultDllImportSearchPathsAttributeTypeSymbol));

                compilationStartAnalysisContext.RegisterSymbolAction(symbolAnalysisContext =>
                {
                    var symbol = symbolAnalysisContext.Symbol;

                    if (!symbol.IsExtern || !symbol.IsStatic)
                    {
                        return;
                    }

                    var dllImportAttribute = symbol.GetAttributes().FirstOrDefault(s => s.AttributeClass.Equals(dllImportAttributeTypeSymbol));
                    var defaultDllImportSearchPathsAttribute = symbol.GetAttributes().FirstOrDefault(s => s.AttributeClass.Equals(defaultDllImportSearchPathsAttributeTypeSymbol));

                    if (dllImportAttribute != null)
                    {
                        var constructorArguments = dllImportAttribute.ConstructorArguments;

                        if (constructorArguments.Length == 0)
                        {
                            return;
                        }

                        if (Path.IsPathRooted(constructorArguments[0].Value.ToString()))
                        {
                            return;
                        }

                        var rule         = UseDefaultDllImportSearchPathsAttributeRule;
                        var ruleArgument = symbol.Name;
                        var validatedDefaultDllImportSearchPathsAttribute = defaultDllImportSearchPathsAttribute ?? defaultDllImportSearchPathsAttributeOnAssembly;

                        if (validatedDefaultDllImportSearchPathsAttribute != null)
                        {
                            var dllImportSearchPath = (int)validatedDefaultDllImportSearchPathsAttribute.ConstructorArguments.FirstOrDefault().Value;
                            var validBits           = dllImportSearchPath & unsafeDllImportSearchPathBits;

                            if (dllImportSearchPath != LegacyBehavior &&
                                validBits == 0)
                            {
                                return;
                            }

                            rule         = DoNotUseUnsafeDllImportSearchPathRule;
                            ruleArgument = ((DllImportSearchPath)validBits).ToString();
                        }

                        symbolAnalysisContext.ReportDiagnostic(
                            symbol.CreateDiagnostic(
                                rule,
                                ruleArgument));
                    }
                }, SymbolKind.Method);
            });
        }
Example #2
0
            static void OnSymbolStart(
                SymbolStartAnalysisContext symbolStartContext,
                WellKnownTypeProvider wellKnownTypeProvider,
                ImmutableArray <INamedTypeSymbol> skippedAttributes,
                bool isWebProject)
            {
                // Since property/event accessors cannot be marked static themselves and the associated symbol (property/event)
                // has to be marked static, we want to report the diagnostic on the property/event.
                // So we make a note of the property/event symbols which have at least one accessor with no instance access.
                // At symbol end, we report candidate property/event symbols whose all accessors are candidates to be marked static.
                var propertyOrEventCandidates = PooledConcurrentSet <ISymbol> .GetInstance();

                var accessorCandidates = PooledConcurrentSet <IMethodSymbol> .GetInstance();

                var methodCandidates = PooledConcurrentSet <IMethodSymbol> .GetInstance();

                // Do not flag methods that are used as delegates: https://github.com/dotnet/roslyn-analyzers/issues/1511
                var methodsUsedAsDelegates = PooledConcurrentSet <IMethodSymbol> .GetInstance();

                symbolStartContext.RegisterOperationAction(OnMethodReference, OperationKind.MethodReference);
                symbolStartContext.RegisterOperationBlockStartAction(OnOperationBlockStart);
                symbolStartContext.RegisterSymbolEndAction(OnSymbolEnd);

                return;

                void OnMethodReference(OperationAnalysisContext operationContext)
                {
                    var methodReference = (IMethodReferenceOperation)operationContext.Operation;

                    methodsUsedAsDelegates.Add(methodReference.Method);
                }

                void OnOperationBlockStart(OperationBlockStartAnalysisContext blockStartContext)
                {
#pragma warning disable IDE0083 // Use pattern matching - need new compiler
                    if (!(blockStartContext.OwningSymbol is IMethodSymbol methodSymbol))
#pragma warning restore IDE0083 // Use pattern matching
                    {
                        return;
                    }

                    // Don't run any other check for this method if it isn't a valid analysis context
                    if (!ShouldAnalyze(methodSymbol, wellKnownTypeProvider, skippedAttributes,
                                       blockStartContext.Options, isWebProject, blockStartContext.CancellationToken))
                    {
                        return;
                    }

                    // Don't report methods which have a single throw statement
                    // with NotImplementedException or NotSupportedException
                    if (blockStartContext.IsMethodNotImplementedOrSupported())
                    {
                        return;
                    }

                    bool isInstanceReferenced = false;

                    blockStartContext.RegisterOperationAction(operationContext =>
                    {
                        if (((IInstanceReferenceOperation)operationContext.Operation).ReferenceKind == InstanceReferenceKind.ContainingTypeInstance)
                        {
                            isInstanceReferenced = true;
                        }
                    }, OperationKind.InstanceReference);

                    blockStartContext.RegisterOperationBlockEndAction(blockEndContext =>
                    {
                        if (!isInstanceReferenced)
                        {
                            if (methodSymbol.IsAccessorMethod())
                            {
                                accessorCandidates.Add(methodSymbol);
                                propertyOrEventCandidates.Add(methodSymbol.AssociatedSymbol);
                            }
                            else if (methodSymbol.IsExternallyVisible())
                            {
                                if (!IsOnObsoleteMemberChain(methodSymbol, wellKnownTypeProvider))
                                {
                                    blockEndContext.ReportDiagnostic(methodSymbol.CreateDiagnostic(Rule, methodSymbol.Name));
                                }
                            }
                            else
                            {
                                methodCandidates.Add(methodSymbol);
                            }
                        }
                    });
                }

                void OnSymbolEnd(SymbolAnalysisContext symbolEndContext)
                {
                    foreach (var candidate in methodCandidates)
                    {
                        if (methodsUsedAsDelegates.Contains(candidate))
                        {
                            continue;
                        }

                        if (!IsOnObsoleteMemberChain(candidate, wellKnownTypeProvider))
                        {
                            symbolEndContext.ReportDiagnostic(candidate.CreateDiagnostic(Rule, candidate.Name));
                        }
                    }

                    foreach (var candidatePropertyOrEvent in propertyOrEventCandidates)
                    {
                        var allAccessorsAreCandidates = true;
                        foreach (var accessor in candidatePropertyOrEvent.GetAccessors())
                        {
                            if (!accessorCandidates.Contains(accessor) ||
                                IsOnObsoleteMemberChain(accessor, wellKnownTypeProvider))
                            {
                                allAccessorsAreCandidates = false;
                                break;
                            }
                        }

                        if (allAccessorsAreCandidates)
                        {
                            symbolEndContext.ReportDiagnostic(candidatePropertyOrEvent.CreateDiagnostic(Rule, candidatePropertyOrEvent.Name));
                        }
                    }

                    propertyOrEventCandidates.Free(symbolEndContext.CancellationToken);
                    accessorCandidates.Free(symbolEndContext.CancellationToken);
                    methodCandidates.Free(symbolEndContext.CancellationToken);
                    methodsUsedAsDelegates.Free(symbolEndContext.CancellationToken);
                }
            }
        /// <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);
        }
        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 wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilationStartAnalysisContext.Compilation);

                if (!wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName(
                        TypeMetadataName,
                        out INamedTypeSymbol? xmlSchemaTypeSymbol))
                {
                    return;
                }

                INamedTypeSymbol?xmlReaderTypeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemXmlXmlReader);

                compilationStartAnalysisContext.RegisterOperationAction(operationAnalysisContext =>
                {
                    var operation = operationAnalysisContext.Operation;
                    IMethodSymbol?methodSymbol = null;
                    string?methodName          = null;

                    switch (operation.Kind)
                    {
                    case OperationKind.Invocation:
                        methodSymbol = ((IInvocationOperation)operation).TargetMethod;
                        methodName   = methodSymbol.Name;
                        break;

                    case OperationKind.ObjectCreation:
                        methodSymbol = ((IObjectCreationOperation)operation).Constructor;
                        methodName   = methodSymbol.ContainingType.Name;
                        break;

                    default:
                        return;
                    }

                    if (methodName.StartsWith(MethodMetadataName, StringComparison.Ordinal) &&
                        methodSymbol.IsOverrideOrVirtualMethodOf(xmlSchemaTypeSymbol))
                    {
                        if (xmlReaderTypeSymbol != null &&
                            !methodSymbol.Parameters.IsEmpty &&
                            methodSymbol.Parameters[0].Type.Equals(xmlReaderTypeSymbol))
                        {
                            return;
                        }

                        operationAnalysisContext.ReportDiagnostic(
                            operation.CreateDiagnostic(
                                Rule,
                                methodSymbol.ContainingType.Name,
                                methodName));
                    }
                }, OperationKind.Invocation, OperationKind.ObjectCreation);
            });
        }
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 compilationStartAnalysisContext) =>
            {
                Compilation?compilation = compilationStartAnalysisContext.Compilation;
                WellKnownTypeProvider wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilation);

                if (!wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName(
                        WellKnownTypeNames.SystemDataDataSet,
                        out INamedTypeSymbol? dataSetTypeSymbol) ||
                    !wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName(
                        WellKnownTypeNames.SystemDataDataTable,
                        out INamedTypeSymbol? dataTableTypeSymbol))
                {
                    return;
                }

                INamedTypeSymbol?webMethodAttributeTypeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(
                    WellKnownTypeNames.SystemWebServicesWebMethodAttribute);
                INamedTypeSymbol?operationContractAttributeTypeSymbol =
                    wellKnownTypeProvider.GetOrCreateTypeByMetadataName(
                        WellKnownTypeNames.SystemServiceModelOperationContractAttribute);

                if (webMethodAttributeTypeSymbol == null && operationContractAttributeTypeSymbol == null)
                {
                    return;
                }

                InsecureDeserializationTypeDecider decider = InsecureDeserializationTypeDecider.GetOrCreate(compilation);

                // Symbol actions for SymbolKind.Method don't seem to trigger on interface methods, so we'll do register
                // for SymbolKind.NamedTypeSymbol instead.
                compilationStartAnalysisContext.RegisterSymbolAction(
                    (SymbolAnalysisContext symbolAnalysisContext) =>
                {
                    INamedTypeSymbol namedTypeSymbol = (INamedTypeSymbol)symbolAnalysisContext.Symbol;
                    if (namedTypeSymbol.TypeKind != TypeKind.Interface &&
                        namedTypeSymbol.TypeKind != TypeKind.Class)
                    {
                        return;
                    }

                    foreach (ISymbol?memberSymbol in namedTypeSymbol.GetMembers())
                    {
                        if (!(memberSymbol is IMethodSymbol methodSymbol))
                        {
                            continue;
                        }

                        ObjectGraphOptions optionsToUse;
                        if (methodSymbol.HasAttribute(webMethodAttributeTypeSymbol))
                        {
                            optionsToUse = ObjectGraphOptions.XmlSerializerOptions;
                        }
                        else if (methodSymbol.HasAttribute(operationContractAttributeTypeSymbol))
                        {
                            optionsToUse = ObjectGraphOptions.DataContractOptions;
                        }
                        else
                        {
                            continue;
                        }

                        foreach (IParameterSymbol parameterSymbol in methodSymbol.Parameters)
                        {
                            if (decider.IsObjectGraphInsecure(
                                    parameterSymbol.Type,
                                    optionsToUse,
                                    out ImmutableArray <InsecureObjectGraphResult> results))
                            {
                                foreach (InsecureObjectGraphResult result in results)
                                {
                                    symbolAnalysisContext.ReportDiagnostic(
                                        Diagnostic.Create(
                                            ObjectGraphContainsDangerousTypeDescriptor,
                                            parameterSymbol.DeclaringSyntaxReferences.First().GetSyntax().GetLocation(),
                                            result.InsecureType.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat),
                                            result.GetDisplayString()));
                                }
                            }
                        }
                    }
                },
                    SymbolKind.NamedType);
            });
        }
        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.TryGetOrCreateTypeByMetadataName(
                    WellKnownTypeNames.MicrosoftWindowsAzureStorageCloudStorageAccount,
                    out INamedTypeSymbol? cloudStorageAccountTypeSymbol);

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

                compilationStartAnalysisContext.RegisterOperationBlockStartAction(operationBlockStartContext =>
                {
                    var owningSymbol = operationBlockStartContext.OwningSymbol;
                    if (operationBlockStartContext.Options.IsConfiguredToSkipAnalysis(Rule, owningSymbol,
                                                                                      operationBlockStartContext.Compilation))
                    {
                        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)
                            {
                                if (invocationOperation.TryGetEnclosingControlFlowGraph(out var cfg))
                                {
                                    var interproceduralAnalysisConfig = InterproceduralAnalysisConfiguration.Create(
                                        operationAnalysisContext.Options,
                                        SupportedDiagnostics,
                                        protocolsArgumentOperation,
                                        operationAnalysisContext.Compilation,
                                        defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.None,
                                        defaultMaxInterproceduralMethodCallChain: 1);
                                    var valueContentAnalysisResult = ValueContentAnalysis.TryGetOrComputeResult(
                                        cfg,
                                        owningSymbol,
                                        operationAnalysisContext.Options,
                                        wellKnownTypeProvider,
                                        PointsToAnalysisKind.Complete,
                                        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 #7
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 compilationStartAnalysisContext) =>
            {
                var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilationStartAnalysisContext.Compilation);
                if (!wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName(
                        WellKnownTypeNames.SystemNetSecurityProtocolType,
                        out var securityProtocolTypeTypeSymbol) ||
                    !wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName(
                        WellKnownTypeNames.SystemNetServicePointManager,
                        out var servicePointManagerTypeSymbol))
                {
                    return;
                }

                compilationStartAnalysisContext.RegisterOperationAction(
                    (OperationAnalysisContext operationAnalysisContext) =>
                {
                    var fieldReferenceOperation = (IFieldReferenceOperation)operationAnalysisContext.Operation;

                    // Make sure we're not inside an &= assignment like:
                    //   ServicePointManager.SecurityProtocol &= ~(SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11)
                    // cuz &= is at worst, disabling protocol versions.
                    if (IsReferencingSecurityProtocolType(
                            fieldReferenceOperation,
                            out var isDeprecatedProtocol,
                            out var isHardCodedOkayProtocol) &&
                        null == fieldReferenceOperation.GetAncestor <ICompoundAssignmentOperation>(
                            OperationKind.CompoundAssignment,
                            IsAndEqualsServicePointManagerAssignment))
                    {
                        if (isDeprecatedProtocol)
                        {
                            operationAnalysisContext.ReportDiagnostic(
                                fieldReferenceOperation.CreateDiagnostic(
                                    DeprecatedRule,
                                    fieldReferenceOperation.Field.Name));
                        }
                        else if (isHardCodedOkayProtocol)
                        {
                            operationAnalysisContext.ReportDiagnostic(
                                fieldReferenceOperation.CreateDiagnostic(
                                    HardCodedRule,
                                    fieldReferenceOperation.Field.Name));
                        }
                    }
                }, OperationKind.FieldReference);

                compilationStartAnalysisContext.RegisterOperationAction(
                    (OperationAnalysisContext operationAnalysisContext) =>
                {
                    var assignmentOperation = (IAssignmentOperation)operationAnalysisContext.Operation;

                    // Make sure this is an assignment operation for a SecurityProtocolType, and not
                    // an assignment like:
                    //   ServicePointManager.SecurityProtocol &= ~(SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11)
                    // cuz &= is at worst, disabling protocol versions.
                    if (!securityProtocolTypeTypeSymbol.Equals(assignmentOperation.Target.Type) ||
                        (assignmentOperation is ICompoundAssignmentOperation compoundAssignmentOperation &&
                         IsAndEqualsServicePointManagerAssignment(compoundAssignmentOperation)))
                    {
                        return;
                    }

                    // Find the topmost operation with a bad bit set, unless we find an operation that would've been
                    // flagged by the FieldReference callback above.
                    IOperation foundDeprecatedOperation = null;
                    bool foundDeprecatedReference       = false;
                    IOperation foundHardCodedOperation  = null;
                    bool foundHardCodedReference        = false;
                    foreach (IOperation childOperation in assignmentOperation.Value.DescendantsAndSelf())
                    {
                        if (childOperation is IFieldReferenceOperation fieldReferenceOperation &&
                            IsReferencingSecurityProtocolType(
                                fieldReferenceOperation,
                                out var isDeprecatedProtocol,
                                out var isHardCodedOkayProtocol))
                        {
                            if (isDeprecatedProtocol)
                            {
                                foundDeprecatedReference = true;
                            }
                            else if (isHardCodedOkayProtocol)
                            {
                                foundHardCodedReference = true;
                            }

                            if (foundDeprecatedReference && foundHardCodedReference)
                            {
                                return;
                            }
                        }

                        if (childOperation.ConstantValue.HasValue &&
                            childOperation.ConstantValue.Value is int integerValue)
                        {
                            if (foundDeprecatedOperation == null &&         // Only want the first.
                                (integerValue & UnsafeBits) != 0)
                            {
                                foundDeprecatedOperation = childOperation;
                            }

                            if (foundHardCodedOperation == null &&         // Only want the first.
                                (integerValue & HardCodedBits) != 0)
                            {
                                foundHardCodedOperation = childOperation;
                            }
                        }
                    }

                    if (foundDeprecatedOperation != null && !foundDeprecatedReference)
                    {
                        operationAnalysisContext.ReportDiagnostic(
                            foundDeprecatedOperation.CreateDiagnostic(
                                DeprecatedRule,
                                foundDeprecatedOperation.ConstantValue));
                    }

                    if (foundHardCodedOperation != null && !foundHardCodedReference)
                    {
                        operationAnalysisContext.ReportDiagnostic(
                            foundHardCodedOperation.CreateDiagnostic(
                                HardCodedRule,
                                foundHardCodedOperation.ConstantValue));
                    }
                },
                    OperationKind.SimpleAssignment,
                    OperationKind.CompoundAssignment);

                return;

                // Local function(s).
                bool IsReferencingSecurityProtocolType(
                    IFieldReferenceOperation fieldReferenceOperation,
                    out bool isDeprecatedProtocol,
                    out bool isHardCodedOkayProtocol)
                {
                    if (securityProtocolTypeTypeSymbol.Equals(fieldReferenceOperation.Field.ContainingType))
                    {
                        if (HardCodedSafeProtocolMetadataNames.Contains(fieldReferenceOperation.Field.Name))
                        {
                            isHardCodedOkayProtocol = true;
                            isDeprecatedProtocol    = false;
                        }
                        else if (fieldReferenceOperation.Field.Name == SystemDefaultName)
                        {
                            isHardCodedOkayProtocol = false;
                            isDeprecatedProtocol    = false;
                        }
                        else
                        {
                            isDeprecatedProtocol    = true;
                            isHardCodedOkayProtocol = false;
                        }

                        return(true);
                    }
                    else
                    {
                        isHardCodedOkayProtocol = false;
                        isDeprecatedProtocol    = false;
                        return(false);
                    }
                }

                bool IsAndEqualsServicePointManagerAssignment(ICompoundAssignmentOperation compoundAssignmentOperation)
                {
                    return(compoundAssignmentOperation.OperatorKind == BinaryOperatorKind.And &&
                           compoundAssignmentOperation.Target is IPropertyReferenceOperation targetPropertyReference &&
                           targetPropertyReference.Instance == null &&
                           servicePointManagerTypeSymbol.Equals(targetPropertyReference.Property.ContainingType) &&
                           targetPropertyReference.Property.MetadataName == "SecurityProtocol");
                }
            });
        }
Example #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);

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

                wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName(
                    WellKnownTypeNames.SystemSecurityCryptographyDSA,
                    out var dsaTypeSymbol);
                wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName(
                    WellKnownTypeNames.SystemSecurityCryptographyAsymmetricAlgorithm,
                    out var asymmetricAlgorithmTypeSymbol);
                wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName(
                    WellKnownTypeNames.SystemSecurityCryptographyCryptoConfig,
                    out var cryptoConfigTypeSymbol);

                if (dsaTypeSymbol == null &&
                    asymmetricAlgorithmTypeSymbol == null &&
                    cryptoConfigTypeSymbol == null)
                {
                    return;
                }

                compilationStartAnalysisContext.RegisterOperationAction(operationAnalysisContext =>
                {
                    var objectCreationOperation = (IObjectCreationOperation)operationAnalysisContext.Operation;
                    var typeSymbol = objectCreationOperation.Constructor.ContainingType;

                    if (typeSymbol == null)
                    {
                        return;
                    }

                    var baseTypesAndThis = typeSymbol.GetBaseTypesAndThis();

                    if (dsaTypeSymbol != null && baseTypesAndThis.Contains(dsaTypeSymbol))
                    {
                        operationAnalysisContext.ReportDiagnostic(
                            objectCreationOperation.CreateDiagnostic(
                                Rule,
                                typeSymbol.Name));
                    }
                }, OperationKind.ObjectCreation);

                compilationStartAnalysisContext.RegisterOperationAction(operationAnalysisContext =>
                {
                    var returnOperation = (IReturnOperation)operationAnalysisContext.Operation;
                    var typeSymbol      = returnOperation.ReturnedValue?.Type;

                    if (typeSymbol == null)
                    {
                        return;
                    }

                    var baseTypesAndThis = typeSymbol.GetBaseTypesAndThis();

                    if (dsaTypeSymbol != null && baseTypesAndThis.Contains(dsaTypeSymbol))
                    {
                        operationAnalysisContext.ReportDiagnostic(
                            returnOperation.CreateDiagnostic(
                                Rule,
                                typeSymbol.Name));
                    }
                }, OperationKind.Return);

                compilationStartAnalysisContext.RegisterOperationAction(operationAnalysisContext =>
                {
                    var invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation;
                    var methodSymbol        = invocationOperation.TargetMethod;
                    var typeSymbol          = methodSymbol.ContainingType;

                    if (typeSymbol == null)
                    {
                        return;
                    }

                    var methodName = methodSymbol.Name;
                    var arguments  = invocationOperation.Arguments;

                    if (methodName == "Create" &&
                        typeSymbol.Equals(asymmetricAlgorithmTypeSymbol) &&
                        arguments.Length > 0 &&
                        arguments[0].Parameter.Type.SpecialType == SpecialType.System_String &&
                        arguments[0].Value.ConstantValue.HasValue)
                    {
                        var argValue = arguments[0].Value.ConstantValue.Value;

                        if (s_DSAAlgorithmNames.Contains(argValue.ToString()))
                        {
                            operationAnalysisContext.ReportDiagnostic(
                                invocationOperation.CreateDiagnostic(
                                    Rule,
                                    argValue));
                        }
                    }
                    else if (methodName == "CreateFromName" &&
                             typeSymbol.Equals(cryptoConfigTypeSymbol) &&
                             arguments.Length > 0 &&
                             arguments[0].Parameter.Type.SpecialType == SpecialType.System_String &&
                             arguments[0].Value.ConstantValue.HasValue)
                    {
                        var argValue = arguments[0].Value.ConstantValue.Value;

                        if (s_DSAAlgorithmNames.Contains(argValue.ToString()))
                        {
                            operationAnalysisContext.ReportDiagnostic(
                                invocationOperation.CreateDiagnostic(
                                    Rule,
                                    argValue));
                        }
                    }
                }, OperationKind.Invocation);
            });
        }
Example #9
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();
                    }
                });
            });
        }
Example #10
0
        public sealed 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) =>
            {
                Compilation?compilation = compilationStartAnalysisContext.Compilation;
                WellKnownTypeProvider wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilation);

                if (!wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName(
                        WellKnownTypeNames.SystemDataDataSet,
                        out INamedTypeSymbol? dataSetTypeSymbol) ||
                    !wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName(
                        WellKnownTypeNames.SystemDataDataTable,
                        out INamedTypeSymbol? dataTableTypeSymbol))
                {
                    return;
                }

                INamedTypeSymbol?dataContractSerializerTypeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(
                    WellKnownTypeNames.SystemRuntimeSerializationDataContractSerializer);
                INamedTypeSymbol?dataContractJsonSerializerTypeSymbol =
                    wellKnownTypeProvider.GetOrCreateTypeByMetadataName(
                        WellKnownTypeNames.SystemRuntimeSerializationJsonDataContractJsonSerializer);
                INamedTypeSymbol?javaScriptSerializerTypeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(
                    WellKnownTypeNames.SystemWebScriptSerializationJavaScriptSerializer);
                INamedTypeSymbol?typeTypeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(
                    WellKnownTypeNames.SystemType);
                INamedTypeSymbol?xmlSerializerTypeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(
                    WellKnownTypeNames.SystemXmlSerializationXmlSerializer);
                INamedTypeSymbol?jsonNetJsonSerializerTypeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(
                    WellKnownTypeNames.NewtonsoftJsonJsonSerializer);
                INamedTypeSymbol?jsonNetJsonConvertTypeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(
                    WellKnownTypeNames.NewtonsoftJsonJsonConvert);

                if (dataContractSerializerTypeSymbol == null &&
                    dataContractJsonSerializerTypeSymbol == null &&
                    javaScriptSerializerTypeSymbol == null &&
                    xmlSerializerTypeSymbol == null &&
                    jsonNetJsonSerializerTypeSymbol == null &&
                    jsonNetJsonConvertTypeSymbol == null)
                {
                    return;
                }

                InsecureDeserializationTypeDecider decider = InsecureDeserializationTypeDecider.GetOrCreate(compilation);

                compilationStartAnalysisContext.RegisterOperationAction(
                    (OperationAnalysisContext operationAnalysisContext) =>
                {
                    IInvocationOperation invocationOperation =
                        (IInvocationOperation)operationAnalysisContext.Operation;
                    if (!IsDeserializationMethod(
                            invocationOperation,
                            out ObjectGraphOptions? optionsToUse,
                            out IEnumerable <(ITypeSymbol DeserializedTypeSymbol, IOperation OperationForLocation)>?deserializedTypes))
                    {
                        return;
                    }

                    RoslynDebug.Assert(optionsToUse != null);
                    RoslynDebug.Assert(deserializedTypes != null);

                    ReportDiagnosticsForInsecureTypes(operationAnalysisContext, optionsToUse, deserializedTypes);
                },
                    OperationKind.Invocation);

                compilationStartAnalysisContext.RegisterOperationAction(
                    (OperationAnalysisContext operationAnalysisContext) =>
                {
                    IObjectCreationOperation objectCreationOperation =
                        (IObjectCreationOperation)operationAnalysisContext.Operation;
                    if (!IsDeserializationConstructor(
                            objectCreationOperation,
                            out ObjectGraphOptions? optionsToUse,
                            out IEnumerable <(ITypeSymbol DeserializedTypeSymbol, IOperation OperationForLocation)>?deserializedTypes))
                    {
                        return;
                    }

                    RoslynDebug.Assert(optionsToUse != null);
                    RoslynDebug.Assert(deserializedTypes != null);

                    ReportDiagnosticsForInsecureTypes(operationAnalysisContext, optionsToUse, deserializedTypes);
                },
                    OperationKind.ObjectCreation);

                return;

                // Local functions.

                // Determines if the invoked method is for deserialization, and what type of deserialization.
                bool IsDeserializationMethod(
                    IInvocationOperation invocationOperation,
                    out ObjectGraphOptions? optionsToUse,
                    out IEnumerable <(ITypeSymbol DeserializedTypeSymbol, IOperation OperationForLocation)>?deserializedTypes)
                {
                    optionsToUse      = null;
                    deserializedTypes = null;

                    IMethodSymbol targetMethod = invocationOperation.TargetMethod;
                    if (invocationOperation.Instance?.Type?.DerivesFrom(javaScriptSerializerTypeSymbol) == true)
                    {
                        if (targetMethod.MetadataName == "DeserializeObject" &&
                            invocationOperation.Parent?.Kind == OperationKind.Conversion &&
                            invocationOperation.Parent is IConversionOperation javaScriptConversionOperation)
                        {
                            optionsToUse      = ObjectGraphOptions.JavaScriptSerializerOptions;
                            deserializedTypes = new[]
                            {
                                (javaScriptConversionOperation.Type, (IOperation)javaScriptConversionOperation)
                            };
                        }
            private static ImmutableHashSet <INamedTypeSymbol> GetIImmutableInterfaces(WellKnownTypeProvider wellKnownTypeProvider)
            {
                var builder = ImmutableHashSet.CreateBuilder <INamedTypeSymbol>();

                builder.AddIfNotNull(wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemCollectionsImmutableIImmutableDictionary2));
                builder.AddIfNotNull(wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemCollectionsImmutableIImmutableList1));
                builder.AddIfNotNull(wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemCollectionsImmutableIImmutableQueue1));
                builder.AddIfNotNull(wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemCollectionsImmutableIImmutableSet1));
                builder.AddIfNotNull(wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemCollectionsImmutableIImmutableStack1));
                return(builder.ToImmutable());
            }
        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 wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilationStartAnalysisContext.Compilation);

                wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName(
                    WellKnownTypeNames.SystemSecurityCryptographyRSA,
                    out var rsaTypeSymbol);
                wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName(
                    WellKnownTypeNames.SystemSecurityCryptographyAsymmetricAlgorithm,
                    out var asymmetricAlgorithmTypeSymbol);
                wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName(
                    WellKnownTypeNames.SystemSecurityCryptographyCryptoConfig,
                    out var cryptoConfigTypeSymbol);

                if (rsaTypeSymbol == null &&
                    asymmetricAlgorithmTypeSymbol == null &&
                    cryptoConfigTypeSymbol == null)
                {
                    return;
                }

                compilationStartAnalysisContext.RegisterOperationAction(operationAnalysisContext =>
                {
                    var objectCreationOperation = (IObjectCreationOperation)operationAnalysisContext.Operation;
                    var typeSymbol = objectCreationOperation.Constructor.ContainingType;

                    if (typeSymbol == null)
                    {
                        return;
                    }

                    var baseTypesAndThis = typeSymbol.GetBaseTypesAndThis();

                    if (rsaTypeSymbol != null && baseTypesAndThis.Contains(rsaTypeSymbol))
                    {
                        var arguments = objectCreationOperation.Arguments;

                        if (arguments.Length == 1 &&
                            arguments[0].Parameter.Type.SpecialType == SpecialType.System_Int32 &&
                            arguments[0].Value.ConstantValue.HasValue &&
                            Convert.ToInt32(arguments[0].Value.ConstantValue.Value, CultureInfo.InvariantCulture) < 2048)
                        {
                            operationAnalysisContext.ReportDiagnostic(
                                objectCreationOperation.CreateDiagnostic(
                                    Rule,
                                    typeSymbol.Name));
                        }
                    }
                }, OperationKind.ObjectCreation);

                compilationStartAnalysisContext.RegisterOperationAction(operationAnalysisContext =>
                {
                    var invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation;
                    var methodSymbol        = invocationOperation.TargetMethod;
                    var typeSymbol          = methodSymbol.ContainingType;

                    if (typeSymbol == null)
                    {
                        return;
                    }

                    var methodName = methodSymbol.Name;
                    var arguments  = invocationOperation.Arguments;

                    if (methodName == "Create" &&
                        typeSymbol.Equals(asymmetricAlgorithmTypeSymbol) &&
                        arguments.Length == 0)
                    {
                        // Use AsymmetricAlgorithm.Create() to create RSA and the default key size is 1024.
                        operationAnalysisContext.ReportDiagnostic(
                            invocationOperation.CreateDiagnostic(
                                Rule,
                                "RSA"));
                    }
                    else if (methodName == "Create" &&
                             typeSymbol.Equals(asymmetricAlgorithmTypeSymbol) &&
                             arguments.Length > 0 &&
                             arguments[0].Parameter.Type.SpecialType == SpecialType.System_String &&
                             arguments[0].Value.ConstantValue.HasValue)
                    {
                        var argValue = arguments[0].Value.ConstantValue.Value;

                        if (s_RSAAlgorithmNames.Contains(argValue.ToString()))
                        {
                            // Use AsymmetricAlgorithm.Create(string) to create RSA and the default key size is 1024.
                            operationAnalysisContext.ReportDiagnostic(
                                invocationOperation.CreateDiagnostic(
                                    Rule,
                                    argValue));
                        }
                    }
                    else if (methodName == "CreateFromName" &&
                             typeSymbol.Equals(cryptoConfigTypeSymbol) &&
                             arguments.Length > 0 &&
                             arguments[0].Parameter.Type.SpecialType == SpecialType.System_String &&
                             arguments[0].Value.ConstantValue.HasValue)
                    {
                        // Use CryptoConfig.CreateFromName(string, ...).
                        var argValue = arguments[0].Value.ConstantValue.Value;

                        if (s_RSAAlgorithmNames.Contains(argValue.ToString()))
                        {
                            // Create RSA.
                            if (arguments.Length == 1 /* The default key size is 1024 */ ||
                                arguments[1].Value is IArrayCreationOperation arrayCreationOperation /* Use CryptoConfig.CreateFromName(string, object[]) to create RSA */ &&
                                arrayCreationOperation.DimensionSizes[0].ConstantValue.Value.Equals(1) &&
                                arrayCreationOperation.Initializer.ElementValues.Any(
                                    s => s is IConversionOperation conversionOperation &&
                                    conversionOperation.Operand.ConstantValue.HasValue &&
                                    Convert.ToInt32(conversionOperation.Operand.ConstantValue.Value, CultureInfo.InvariantCulture) < 2048) /* Specify the key size is smaller than 2048 explicitly */)
                            {
                                operationAnalysisContext.ReportDiagnostic(
                                    invocationOperation.CreateDiagnostic(
                                        Rule,
                                        argValue));
                            }
                        }
                    }
                }, OperationKind.Invocation);
            });
        }
        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));
        }
Example #14
0
 internal static void AddCoupledNamedTypes(ImmutableHashSet <INamedTypeSymbol> .Builder builder, WellKnownTypeProvider wellKnownTypeProvider,
                                           ImmutableArray <IParameterSymbol> parameters)
 {
     foreach (var parameter in parameters)
     {
         AddCoupledNamedTypesCore(builder, parameter.Type, wellKnownTypeProvider);
     }
 }
Example #15
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 (owningSymbol.IsConfiguredToSkipAnalysis(options, TaintedDataEnteringSinkDescriptor, compilation, cancellationToken))
                    {
                        return;
                    }

                    WellKnownTypeProvider wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilation);
                    InterproceduralAnalysisConfiguration interproceduralAnalysisConfiguration = InterproceduralAnalysisConfiguration.Create(
                        options,
                        SupportedDiagnostics,
                        defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.ContextSensitive,
                        cancellationToken: cancellationToken);
                    Lazy <ControlFlowGraph> controlFlowGraphFactory = new Lazy <ControlFlowGraph>(
                        () => operationBlockStartContext.OperationBlocks.GetControlFlowGraph());
                    Lazy <PointsToAnalysisResult> pointsToFactory = new Lazy <PointsToAnalysisResult>(
                        () =>
                    {
                        if (controlFlowGraphFactory.Value == null)
                        {
                            return(null);
                        }

                        return(PointsToAnalysis.TryGetOrComputeResult(
                                   controlFlowGraphFactory.Value,
                                   owningSymbol,
                                   options,
                                   wellKnownTypeProvider,
                                   interproceduralAnalysisConfiguration,
                                   interproceduralAnalysisPredicateOpt: null));
                    });
                    Lazy <(PointsToAnalysisResult, ValueContentAnalysisResult)> valueContentFactory = new Lazy <(PointsToAnalysisResult, ValueContentAnalysisResult)>(
                        () =>
                    {
                        if (controlFlowGraphFactory.Value == null)
                        {
                            return(null, null);
                        }

                        ValueContentAnalysisResult valuecontentAnalysisResult = ValueContentAnalysis.TryGetOrComputeResult(
                            controlFlowGraphFactory.Value,
                            owningSymbol,
                            options,
                            wellKnownTypeProvider,
                            interproceduralAnalysisConfiguration,
                            out _,
                            out PointsToAnalysisResult p);

                        return(p, valuecontentAnalysisResult);
                    });

                    PooledHashSet <IOperation> rootOperationsNeedingAnalysis = PooledHashSet <IOperation> .GetInstance();

                    operationBlockStartContext.RegisterOperationAction(
                        operationAnalysisContext =>
                    {
                        IPropertyReferenceOperation propertyReferenceOperation = (IPropertyReferenceOperation)operationAnalysisContext.Operation;
                        if (sourceInfoSymbolMap.IsSourceProperty(propertyReferenceOperation.Property))
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                rootOperationsNeedingAnalysis.Add(propertyReferenceOperation.GetRoot());
                            }
                        }
                    },
                        OperationKind.PropertyReference);

                    operationBlockStartContext.RegisterOperationAction(
                        operationAnalysisContext =>
                    {
                        IInvocationOperation invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation;
                        if (sourceInfoSymbolMap.IsSourceMethod(
                                invocationOperation.TargetMethod,
                                invocationOperation.Arguments,
                                pointsToFactory,
                                valueContentFactory,
                                out _))
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                rootOperationsNeedingAnalysis.Add(invocationOperation.GetRoot());
                            }
                        }
                    },
                        OperationKind.Invocation);

                    if (taintedDataConfig.HasTaintArraySource(SinkKind))
                    {
                        operationBlockStartContext.RegisterOperationAction(
                            operationAnalysisContext =>
                        {
                            IArrayInitializerOperation arrayInitializerOperation = (IArrayInitializerOperation)operationAnalysisContext.Operation;
                            if (arrayInitializerOperation.GetAncestor <IArrayCreationOperation>(OperationKind.ArrayCreation)?.Type is IArrayTypeSymbol arrayTypeSymbol &&
                                sourceInfoSymbolMap.IsSourceConstantArrayOfType(arrayTypeSymbol))
                            {
                                lock (rootOperationsNeedingAnalysis)
                                {
                                    rootOperationsNeedingAnalysis.Add(operationAnalysisContext.Operation.GetRoot());
                                }
                            }
                        },
                            OperationKind.ArrayInitializer);
                    }

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

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

                                foreach (IOperation rootOperation in rootOperationsNeedingAnalysis)
                                {
                                    TaintedDataAnalysisResult taintedDataAnalysisResult = TaintedDataAnalysis.TryGetOrComputeResult(
                                        controlFlowGraphFactory.Value,
                                        operationBlockAnalysisContext.Compilation,
                                        operationBlockAnalysisContext.OwningSymbol,
                                        operationBlockAnalysisContext.Options,
                                        TaintedDataEnteringSinkDescriptor,
                                        sourceInfoSymbolMap,
                                        taintedDataConfig.GetSanitizerSymbolMap(this.SinkKind),
                                        sinkInfoSymbolMap,
                                        operationBlockAnalysisContext.CancellationToken);
                                    if (taintedDataAnalysisResult == null)
                                    {
                                        return;
                                    }

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

                                        foreach (SymbolAccess sourceOrigin in sourceSink.SourceOrigins)
                                        {
                                            // Something like:
                                            // CA3001: Potential SQL injection vulnerability was found where '{0}' in method '{1}' may be tainted by user-controlled data from '{2}' in method '{3}'.
                                            Diagnostic diagnostic = Diagnostic.Create(
                                                this.TaintedDataEnteringSinkDescriptor,
                                                sourceSink.Sink.Location,
                                                additionalLocations: new Location[] { sourceOrigin.Location },
                                                messageArgs: new object[] {
                                                sourceSink.Sink.Symbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat),
                                                sourceSink.Sink.AccessingMethod.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat),
                                                sourceOrigin.Symbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat),
                                                sourceOrigin.AccessingMethod.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat)
                                            });
                                            operationBlockAnalysisContext.ReportDiagnostic(diagnostic);
                                        }
                                    }
                                }
                            }
                        }
                        finally
                        {
                            rootOperationsNeedingAnalysis.Free();
                        }
                    });
                });
            });
        }
        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();
                    }
                });
            });
        }
        public override void Initialize(AnalysisContext context)
        {
            context.EnableConcurrentExecution();
            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);

            context.RegisterCompilationStartAction(compilationContext =>
            {
                compilationContext.RegisterOperationBlockAction(operationBlockContext =>
                {
                    var owningSymbol            = operationBlockContext.OwningSymbol;
                    var processedOperationRoots = new HashSet <IOperation>();

                    foreach (var operationRoot in operationBlockContext.OperationBlocks)
                    {
                        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.GetOrComputeResult(cfg, owningSymbol, wellKnownTypeProvider,
                                                                                                     operationBlockContext.Options, AlwaysTrueFalseOrNullRule, operationBlockContext.CancellationToken,
                                                                                                     out var copyAnalysisResultOpt, out var pointsToAnalysisResult,
                                                                                                     performCopyAnalysisIfNotUserConfigured: false); // TODO: Enable copy analysis by default.

                            Debug.Assert(pointsToAnalysisResult != null);

                            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 IBinaryOperation leftBinary) || GetPredicateKind(leftBinary) == PredicateValueKind.Unknown) &&
                                        (!(binaryOperation.RightOperand is 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)
                                    {
                                        // Skip compiler generated IsNull operation for assignment 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 == OperationKind.BinaryOperator ||
                                             operation.Kind == OperationKind.Invocation ||
                                             operation.Kind == OperationKind.IsNull ||
                                             operation.Kind == OperationKind.IsPattern);

                                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);
                            }
                        }
                    }
                });
            });
        }
Example #18
0
 public AttributesAnalyzer(DiagnosticDescriptor rule, WellKnownTypeProvider wellKnownTypeProvider)
 {
     Rule = rule;
     WellKnownTypeProvider = wellKnownTypeProvider;
 }
Example #19
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();
                        }
                    });
                });
            });
        }
Example #20
0
        public override void Initialize(AnalysisContext context)
        {
            context.EnableConcurrentExecution();
            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);

            context.RegisterCompilationStartAction(compilationContext =>
            {
                var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilationContext.Compilation);
                INamedTypeSymbol?cancellationTokenType = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingCancellationToken);
                INamedTypeSymbol?iprogressType         = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemIProgress1);
                if (cancellationTokenType == null)
                {
                    return;
                }

                compilationContext.RegisterSymbolAction(symbolContext =>
                {
                    var methodSymbol = (IMethodSymbol)symbolContext.Symbol;
                    if (methodSymbol.IsOverride ||
                        methodSymbol.IsImplementationOfAnyInterfaceMember())
                    {
                        return;
                    }

                    int last = methodSymbol.Parameters.Length - 1;
                    if (last >= 0 && methodSymbol.Parameters[last].IsParams)
                    {
                        last--;
                    }

                    // Skip optional parameters, UNLESS one of them is a CancellationToken
                    // AND it's not the last one.
                    if (last >= 0 && methodSymbol.Parameters[last].IsOptional &&
                        !methodSymbol.Parameters[last].Type.Equals(cancellationTokenType))
                    {
                        last--;

                        while (last >= 0 && methodSymbol.Parameters[last].IsOptional)
                        {
                            if (methodSymbol.Parameters[last].Type.Equals(cancellationTokenType))
                            {
                                symbolContext.ReportDiagnostic(Diagnostic.Create(
                                                                   Rule, methodSymbol.Locations.First(), methodSymbol.ToDisplayString()));
                            }

                            last--;
                        }
                    }

                    // Ignore multiple cancellation token parameters at the end of the parameter list.
                    while (last >= 0 && methodSymbol.Parameters[last].Type.Equals(cancellationTokenType))
                    {
                        last--;
                    }

                    // Ignore parameters passed by reference when they appear at the end of the parameter list.
                    while (last >= 0 && methodSymbol.Parameters[last].RefKind != RefKind.None)
                    {
                        last--;
                    }

                    // Ignore IProgress<T> when last
                    if (last >= 0 &&
                        iprogressType != null &&
                        methodSymbol.Parameters[last].Type.OriginalDefinition.Equals(iprogressType))
                    {
                        last--;
                    }

                    for (int i = last - 1; i >= 0; i--)
                    {
                        ITypeSymbol parameterType = methodSymbol.Parameters[i].Type;
                        if (!parameterType.Equals(cancellationTokenType))
                        {
                            continue;
                        }

                        // Bail if the CancellationToken is the first parameter of an extension method.
                        if (i == 0 && methodSymbol.IsExtensionMethod)
                        {
                            continue;
                        }

                        symbolContext.ReportDiagnostic(Diagnostic.Create(
                                                           Rule, methodSymbol.Locations.First(), methodSymbol.ToDisplayString()));
                        break;
                    }
                },
                                                        SymbolKind.Method);
            });
        }
        public sealed 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) =>
            {
                Compilation?compilation = compilationStartAnalysisContext.Compilation;
                WellKnownTypeProvider wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilation);

                if (!wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName(
                        WellKnownTypeNames.SystemDataDataSet,
                        out INamedTypeSymbol? dataSetTypeSymbol) ||
                    !wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName(
                        WellKnownTypeNames.SystemDataDataTable,
                        out INamedTypeSymbol? dataTableTypeSymbol))
                {
                    return;
                }

                INamedTypeSymbol?serializableAttributeTypeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(
                    WellKnownTypeNames.SystemSerializableAttribute);
                INamedTypeSymbol?nonSerializedAttributeTypeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(
                    WellKnownTypeNames.SystemSerializableAttribute);
                INamedTypeSymbol?binaryFormatterTypeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(
                    WellKnownTypeNames.SystemRuntimeSerializationFormattersBinaryBinaryFormatter);
                INamedTypeSymbol?netDataContractSerializerTypeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(
                    WellKnownTypeNames.SystemRuntimeSerializationNetDataContractSerializer);
                INamedTypeSymbol?objectStateFormatterTypeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(
                    WellKnownTypeNames.SystemWebUIObjectStateFormatter);
                INamedTypeSymbol?soapFormatterTypeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(
                    WellKnownTypeNames.SystemRuntimeSerializationFormattersSoapSoapFormatter);

                if (serializableAttributeTypeSymbol == null ||
                    (binaryFormatterTypeSymbol == null &&
                     netDataContractSerializerTypeSymbol == null &&
                     objectStateFormatterTypeSymbol == null &&
                     soapFormatterTypeSymbol == null))
                {
                    return;
                }

                InsecureDeserializationTypeDecider decider = InsecureDeserializationTypeDecider.GetOrCreate(compilation);

                compilationStartAnalysisContext.RegisterOperationAction(
                    (OperationAnalysisContext operationAnalysisContext) =>
                {
                    IInvocationOperation invocationOperation =
                        (IInvocationOperation)operationAnalysisContext.Operation;
                    string methodName = invocationOperation.TargetMethod.MetadataName;
                    if (!(((invocationOperation.Instance?.Type?.DerivesFrom(binaryFormatterTypeSymbol) == true &&
                            SecurityHelpers.BinaryFormatterDeserializationMethods.Contains(methodName)) ||
                           (invocationOperation.Instance?.Type?.DerivesFrom(netDataContractSerializerTypeSymbol) == true &&
                            SecurityHelpers.NetDataContractSerializerDeserializationMethods.Contains(methodName)) ||
                           (invocationOperation.Instance?.Type?.DerivesFrom(objectStateFormatterTypeSymbol) == true &&
                            SecurityHelpers.ObjectStateFormatterDeserializationMethods.Contains(methodName)) ||
                           (invocationOperation.Instance?.Type?.DerivesFrom(soapFormatterTypeSymbol) == true &&
                            SecurityHelpers.SoapFormatterDeserializationMethods.Contains(methodName))) &&
                          invocationOperation.Parent?.Kind == OperationKind.Conversion &&
                          invocationOperation.Parent is IConversionOperation conversionOperation))
                    {
                        return;
                    }

                    ITypeSymbol deserializedType = conversionOperation.Type;

                    ObjectGraphOptions options;
                    if (invocationOperation.Instance?.Type?.DerivesFrom(netDataContractSerializerTypeSymbol) == true)
                    {
                        options = ObjectGraphOptions.DataContractOptions;
                    }
                    else
                    {
                        options = ObjectGraphOptions.BinarySerializationOptions;
                    }

                    if (decider.IsObjectGraphInsecure(
                            deserializedType,
                            options,
                            out ImmutableArray <InsecureObjectGraphResult> results))
                    {
                        foreach (InsecureObjectGraphResult result in results)
                        {
                            operationAnalysisContext.ReportDiagnostic(
                                Diagnostic.Create(
                                    ObjectGraphContainsDangerousTypeDescriptor,
                                    invocationOperation.Parent.Syntax.GetLocation(),
                                    result.InsecureType.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat),
                                    result.GetDisplayString(typedConstant => ToString(typedConstant))));
                        }
                    }
                },
                    OperationKind.Invocation);
            });
        }
Example #22
0
        private static TaintedDataConfig Create(Compilation compilation)
        {
            WellKnownTypeProvider wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilation);

            using PooledDictionary <SinkKind, Lazy <TaintedDataSymbolMap <SourceInfo> > > sourceSymbolMapBuilder =
                      PooledDictionary <SinkKind, Lazy <TaintedDataSymbolMap <SourceInfo> > > .GetInstance();

            using PooledDictionary <SinkKind, Lazy <TaintedDataSymbolMap <SanitizerInfo> > > sanitizerSymbolMapBuilder =
                      PooledDictionary <SinkKind, Lazy <TaintedDataSymbolMap <SanitizerInfo> > > .GetInstance();

            using PooledDictionary <SinkKind, Lazy <TaintedDataSymbolMap <SinkInfo> > > sinkSymbolMapBuilder =
                      PooledDictionary <SinkKind, Lazy <TaintedDataSymbolMap <SinkInfo> > > .GetInstance();

            // For tainted data rules with the same set of sources, we'll reuse the same TaintedDataSymbolMap<SourceInfo> instance.
            // Same for sanitizers.
            using PooledDictionary <ImmutableHashSet <SourceInfo>, Lazy <TaintedDataSymbolMap <SourceInfo> > > sourcesToSymbolMap =
                      PooledDictionary <ImmutableHashSet <SourceInfo>, Lazy <TaintedDataSymbolMap <SourceInfo> > > .GetInstance();

            using PooledDictionary <ImmutableHashSet <SanitizerInfo>, Lazy <TaintedDataSymbolMap <SanitizerInfo> > > sanitizersToSymbolMap =
                      PooledDictionary <ImmutableHashSet <SanitizerInfo>, Lazy <TaintedDataSymbolMap <SanitizerInfo> > > .GetInstance();

            // Build a mapping of (sourceSet, sanitizerSet) -> (sinkKinds, sinkSet), so we'll reuse the same TaintedDataSymbolMap<SinkInfo> instance.
            using PooledDictionary <(ImmutableHashSet <SourceInfo> SourceInfos, ImmutableHashSet <SanitizerInfo> SanitizerInfos), (ImmutableHashSet <SinkKind> .Builder SinkKinds, ImmutableHashSet <SinkInfo> .Builder SinkInfos)> sourceSanitizersToSinks =
                      PooledDictionary <(ImmutableHashSet <SourceInfo> SourceInfos, ImmutableHashSet <SanitizerInfo> SanitizerInfos), (ImmutableHashSet <SinkKind> .Builder SinkKinds, ImmutableHashSet <SinkInfo> .Builder SinkInfos)> .GetInstance();

            // Using LazyThreadSafetyMode.ExecutionAndPublication to avoid instantiating multiple times.
            foreach (SinkKind sinkKind in Enum.GetValues(typeof(SinkKind)))
            {
                ImmutableHashSet <SourceInfo> sources = GetSourceInfos(sinkKind);
                if (!sourcesToSymbolMap.TryGetValue(sources, out Lazy <TaintedDataSymbolMap <SourceInfo> > lazySourceSymbolMap))
                {
                    lazySourceSymbolMap = new Lazy <TaintedDataSymbolMap <SourceInfo> >(
                        () => { return(new TaintedDataSymbolMap <SourceInfo>(wellKnownTypeProvider, sources)); },
                        LazyThreadSafetyMode.ExecutionAndPublication);
                    sourcesToSymbolMap.Add(sources, lazySourceSymbolMap);
                }

                sourceSymbolMapBuilder.Add(sinkKind, lazySourceSymbolMap);

                ImmutableHashSet <SanitizerInfo> sanitizers = GetSanitizerInfos(sinkKind);
                if (!sanitizersToSymbolMap.TryGetValue(sanitizers, out Lazy <TaintedDataSymbolMap <SanitizerInfo> > lazySanitizerSymbolMap))
                {
                    lazySanitizerSymbolMap = new Lazy <TaintedDataSymbolMap <SanitizerInfo> >(
                        () => { return(new TaintedDataSymbolMap <SanitizerInfo>(wellKnownTypeProvider, sanitizers)); },
                        LazyThreadSafetyMode.ExecutionAndPublication);
                    sanitizersToSymbolMap.Add(sanitizers, lazySanitizerSymbolMap);
                }

                sanitizerSymbolMapBuilder.Add(sinkKind, lazySanitizerSymbolMap);

                ImmutableHashSet <SinkInfo> sinks = GetSinkInfos(sinkKind);
                if (!sourceSanitizersToSinks.TryGetValue((sources, sanitizers), out (ImmutableHashSet <SinkKind> .Builder SinkKinds, ImmutableHashSet <SinkInfo> .Builder SinkInfos)sinksPair))
                {
                    sinksPair = (ImmutableHashSet.CreateBuilder <SinkKind>(), ImmutableHashSet.CreateBuilder <SinkInfo>());
                    sourceSanitizersToSinks.Add((sources, sanitizers), sinksPair);
                }

                sinksPair.SinkKinds.Add(sinkKind);
                sinksPair.SinkInfos.UnionWith(sinks);
            }

            foreach (KeyValuePair <(ImmutableHashSet <SourceInfo> SourceInfos, ImmutableHashSet <SanitizerInfo> SanitizerInfos), (ImmutableHashSet <SinkKind> .Builder SinkKinds, ImmutableHashSet <SinkInfo> .Builder SinkInfos)> kvp in sourceSanitizersToSinks)
            {
                ImmutableHashSet <SinkInfo>             sinks             = kvp.Value.SinkInfos.ToImmutable();
                Lazy <TaintedDataSymbolMap <SinkInfo> > lazySinkSymbolMap = new Lazy <TaintedDataSymbolMap <SinkInfo> >(
                    () => { return(new TaintedDataSymbolMap <SinkInfo>(wellKnownTypeProvider, sinks)); },
                    LazyThreadSafetyMode.ExecutionAndPublication);
                foreach (SinkKind sinkKind in kvp.Value.SinkKinds)
                {
                    sinkSymbolMapBuilder.Add(sinkKind, lazySinkSymbolMap);
                }
            }

            return(new TaintedDataConfig(
                       wellKnownTypeProvider,
                       sourceSymbolMapBuilder.ToImmutableDictionary(),
                       sanitizerSymbolMapBuilder.ToImmutableDictionary(),
                       sinkSymbolMapBuilder.ToImmutableDictionary()));
        }
        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 =>
            {
                Compilation compilation   = compilationStartAnalysisContext.Compilation;
                var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilationStartAnalysisContext.Compilation);

                if (!wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemWebUIPage, out var pageTypeSymbol) ||
                    !wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemEventArgs, out var eventArgsTypeSymbol))
                {
                    return;
                }

                compilationStartAnalysisContext.RegisterSymbolAction(symbolAnalysisContext =>
                {
                    var classSymbol     = (INamedTypeSymbol)symbolAnalysisContext.Symbol;
                    var baseClassSymbol = classSymbol.BaseType;

                    if (pageTypeSymbol.Equals(baseClassSymbol))
                    {
                        var methods = classSymbol.GetMembers().OfType <IMethodSymbol>();
                        var setViewStateUserKeyInOnInit = SetViewStateUserKeyCorrectly(methods.FirstOrDefault(s => s.Name == "OnInit" &&
                                                                                                              s.Parameters.Length == 1 &&
                                                                                                              s.Parameters[0].Type.Equals(eventArgsTypeSymbol) &&
                                                                                                              s.IsProtected() &&
                                                                                                              !s.IsStatic));
                        var setViewStateUserKeyInPage_Init = SetViewStateUserKeyCorrectly(methods.FirstOrDefault(s => s.Name == "Page_Init" &&
                                                                                                                 s.Parameters.Length == 2 &&
                                                                                                                 s.Parameters[0].Type.SpecialType == SpecialType.System_Object &&
                                                                                                                 s.Parameters[1].Type.Equals(eventArgsTypeSymbol) &&
                                                                                                                 s.ReturnType.SpecialType == SpecialType.System_Void));

                        if (setViewStateUserKeyInOnInit || setViewStateUserKeyInPage_Init)
                        {
                            return;
                        }

                        symbolAnalysisContext.ReportDiagnostic(
                            classSymbol.CreateDiagnostic(
                                Rule,
                                classSymbol.Name));
                    }
                }, SymbolKind.NamedType);

                bool SetViewStateUserKeyCorrectly(IMethodSymbol methodSymbol)
                {
                    return(methodSymbol?.GetTopmostOperationBlock(compilation)
                           .Descendants()
                           .Any(s => s is ISimpleAssignmentOperation simpleAssignmentOperation &&
                                simpleAssignmentOperation.Target is IPropertyReferenceOperation propertyReferenceOperation &&
                                propertyReferenceOperation.Property.Name == "ViewStateUserKey" &&
                                propertyReferenceOperation.Property.Type.SpecialType == SpecialType.System_String &&
                                (propertyReferenceOperation.Instance is IInstanceReferenceOperation instanceReferenceOperation &&
                                 instanceReferenceOperation.ReferenceKind == InstanceReferenceKind.ContainingTypeInstance ||
                                 propertyReferenceOperation.Instance is IPropertyReferenceOperation propertyReferenceOperation2 &&
                                 propertyReferenceOperation2.Property.IsVirtual &&
                                 propertyReferenceOperation2.Instance is IInstanceReferenceOperation instanceReferenceOperation2 &&
                                 instanceReferenceOperation2.ReferenceKind == InstanceReferenceKind.ContainingTypeInstance))
                           ?? false);
                }
            });
        }
Example #24
0
        public override void Initialize(AnalysisContext analysisContext)
        {
            analysisContext.EnableConcurrentExecution();
            analysisContext.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);

            analysisContext.RegisterCompilationStartAction(
                (CompilationStartAnalysisContext compilationStartContext) =>
            {
                WellKnownTypeProvider wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilationStartContext.Compilation);
                INamedTypeSymbol?mvcControllerSymbol        = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemWebMvcController);
                INamedTypeSymbol?mvcControllerBaseSymbol    = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemWebMvcControllerBase);
                INamedTypeSymbol?actionResultSymbol         = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemWebMvcActionResult);

                if ((mvcControllerSymbol == null && mvcControllerBaseSymbol == null) || actionResultSymbol == null)
                {
                    // No MVC controllers that return an ActionResult here.
                    return;
                }

                MvcAttributeSymbols mvcAttributeSymbols = new MvcAttributeSymbols(compilationStartContext.Compilation);

                compilationStartContext.RegisterSymbolAction(
                    (SymbolAnalysisContext symbolContext) =>
                {
                    // TODO enhancements: Consider looking at IAsyncResult-based action methods.
                    if (symbolContext.Symbol is not IMethodSymbol methodSymbol ||
                        methodSymbol.MethodKind != MethodKind.Ordinary ||
                        methodSymbol.IsStatic ||
                        !methodSymbol.IsPublic() ||
                        !(methodSymbol.ReturnType.Inherits(actionResultSymbol) ||          // FxCop implementation only looked at ActionResult-derived return types.
                          wellKnownTypeProvider.IsTaskOfType(
                              methodSymbol.ReturnType,
                              (ITypeSymbol typeArgument) => typeArgument.Inherits(actionResultSymbol))) ||
                        (!methodSymbol.ContainingType.Inherits(mvcControllerSymbol) &&
                         !methodSymbol.ContainingType.Inherits(mvcControllerBaseSymbol)))
                    {
                        return;
                    }

                    ImmutableArray <AttributeData> methodAttributes = methodSymbol.GetAttributes();
                    mvcAttributeSymbols.ComputeAttributeInfo(methodAttributes, out var verbs, out var isAntiforgeryTokenDefined, out var isAction);

                    if (!isAction)
                    {
                        return;
                    }

                    if (verbs == MvcHttpVerbs.None)
                    {
                        // no verbs specified
                        if (isAntiforgeryTokenDefined)
                        {
                            // antiforgery token attribute is set, but verbs are not specified
                            symbolContext.ReportDiagnostic(Diagnostic.Create(NoVerbsRule, methodSymbol.Locations[0], methodSymbol.MetadataName));
                        }
                        else
                        {
                            // no verbs, no antiforgery token attribute
                            symbolContext.ReportDiagnostic(Diagnostic.Create(NoVerbsNoTokenRule, methodSymbol.Locations[0], methodSymbol.MetadataName));
                        }
                    }
                    else
                    {
                        // verbs are defined
                        if (isAntiforgeryTokenDefined)
                        {
                            if (verbs.HasFlag(MvcHttpVerbs.Get))
                            {
                                symbolContext.ReportDiagnostic(Diagnostic.Create(GetAndTokenRule, methodSymbol.Locations[0], methodSymbol.MetadataName));

                                if ((verbs & (MvcHttpVerbs.Post | MvcHttpVerbs.Put | MvcHttpVerbs.Delete | MvcHttpVerbs.Patch)) != MvcHttpVerbs.None)
                                {
                                    // both verbs, antiforgery token attribute
                                    symbolContext.ReportDiagnostic(Diagnostic.Create(GetAndOtherAndTokenRule, methodSymbol.Locations[0], methodSymbol.MetadataName));
                                }
                            }
                        }
                        else
                        {
                            if ((verbs & (MvcHttpVerbs.Post | MvcHttpVerbs.Put | MvcHttpVerbs.Delete | MvcHttpVerbs.Patch)) != MvcHttpVerbs.None)
                            {
                                // HttpPost, no antiforgery token attribute
                                symbolContext.ReportDiagnostic(Diagnostic.Create(VerbsAndNoTokenRule, methodSymbol.Locations[0], methodSymbol.MetadataName));
                            }
                        }
                    }
                },
                    SymbolKind.Method);
            }
                );
        }
        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();
                    }
                });
            });
        }
 /// <summary>
 /// Gets a type by its full type name and cache it at the compilation level.
 /// </summary>
 /// <param name="compilation">The compilation.</param>
 /// <param name="fullTypeName">Namespace + type name, e.g. "System.Exception".</param>
 /// <returns>The <see cref="INamedTypeSymbol"/> if found, null otherwise.</returns>
 internal static INamedTypeSymbol?GetOrCreateTypeByMetadataName(this Compilation compilation, string fullTypeName) =>
 WellKnownTypeProvider.GetOrCreate(compilation).GetOrCreateTypeByMetadataName(fullTypeName);
 /// <summary>
 /// Initializes a new instance of the <see cref="OperationActionsContext"/> class.
 /// </summary>
 /// <param name="compilation">The compilation.</param>
 /// <param name="enumerableType">Type of the enumerable.</param>
 public OperationActionsContext(Compilation compilation, INamedTypeSymbol enumerableType)
 {
     EnumerableType         = enumerableType;
     _wellKnownTypeProvider = new Lazy <WellKnownTypeProvider>(() => WellKnownTypeProvider.GetOrCreate(compilation), true);
     _immutableArrayType    = new Lazy <INamedTypeSymbol>(() => _wellKnownTypeProvider.Value.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemCollectionsImmutableImmutableArray), true);
 }
 /// <summary>
 /// Gets a type by its full type name and cache it at the compilation level.
 /// </summary>
 /// <param name="compilation">The compilation.</param>
 /// <param name="fullTypeName">Namespace + type name, e.g. "System.Exception".</param>
 /// <returns>The <see cref="INamedTypeSymbol"/> if found, null otherwise.</returns>
 internal static bool TryGetOrCreateTypeByMetadataName(this Compilation compilation, string fullTypeName, [NotNullWhen(returnValue: true)] out INamedTypeSymbol?namedTypeSymbol) =>
 WellKnownTypeProvider.GetOrCreate(compilation).TryGetOrCreateTypeByMetadataName(fullTypeName, out namedTypeSymbol);
Example #29
0
 internal static void AddCoupledNamedTypes(ImmutableHashSet <INamedTypeSymbol> .Builder builder, WellKnownTypeProvider wellKnownTypeProvider,
                                           params ITypeSymbol[] coupledTypes)
 {
     foreach (var coupledType in coupledTypes)
     {
         AddCoupledNamedTypesCore(builder, coupledType, wellKnownTypeProvider);
     }
 }
        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 compilation           = compilationStartAnalysisContext.Compilation;
                var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilationStartAnalysisContext.Compilation);

                if (!wellKnownTypeProvider.TryGetTypeByMetadataName(WellKnownTypeNames.MicrosoftAspNetCoreMvcFiltersFilterCollection, out var filterCollectionTypeSymbol) ||
                    !wellKnownTypeProvider.TryGetTypeByMetadataName(WellKnownTypeNames.MicrosoftAspNetCoreMvcController, out var controllerTypeSymbol) ||
                    !wellKnownTypeProvider.TryGetTypeByMetadataName(WellKnownTypeNames.MicrosoftAspNetCoreMvcControllerBase, out var controllerBaseTypeSymbol) ||
                    !wellKnownTypeProvider.TryGetTypeByMetadataName(WellKnownTypeNames.MicrosoftAspNetCoreMvcNonActionAttribute, out var nonActionAttributeTypeSymbol) ||
                    !wellKnownTypeProvider.TryGetTypeByMetadataName(WellKnownTypeNames.MicrosoftAspNetCoreMvcRoutingHttpMethodAttribute, out var httpMethodAttributeTypeSymbol) ||
                    !wellKnownTypeProvider.TryGetTypeByMetadataName(WellKnownTypeNames.MicrosoftAspNetCoreMvcFiltersIFilterMetadata, out var iFilterMetadataTypeSymbol) ||
                    !wellKnownTypeProvider.TryGetTypeByMetadataName(WellKnownTypeNames.MicrosoftAspNetCoreAntiforgeryIAntiforgery, out var iAntiforgeryTypeSymbol) ||
                    !wellKnownTypeProvider.TryGetTypeByMetadataName(WellKnownTypeNames.MicrosoftAspNetCoreMvcFiltersIAsyncAuthorizationFilter, out var iAsyncAuthorizationFilterTypeSymbol) ||
                    !wellKnownTypeProvider.TryGetTypeByMetadataName(WellKnownTypeNames.MicrosoftAspNetCoreMvcFiltersIAuthorizationFilter, out var iAuthorizationFilterTypeSymbol) ||
                    !wellKnownTypeProvider.TryGetTypeByMetadataName(WellKnownTypeNames.SystemThreadingTasksTask, out var taskTypeSymbol) ||
                    !wellKnownTypeProvider.TryGetTypeByMetadataName(WellKnownTypeNames.MicrosoftAspNetCoreMvcFiltersAuthorizationFilterContext, out var authorizationFilterContextTypeSymbol))
                {
                    return;
                }

                var httpVerbAttributeTypeSymbolsAbleToModify = HttpVerbAttributesMarkingOnActionModifyingMethods.Select(
                    s => wellKnownTypeProvider.TryGetTypeByMetadataName(s, out var attributeTypeSymbol) ? attributeTypeSymbol : null);

                if (httpVerbAttributeTypeSymbolsAbleToModify.Any(s => s == null))
                {
                    return;
                }

                // A dictionary from method symbol to set of methods calling it directly.
                // The bool value in the sub ConcurrentDictionary is not used, use ConcurrentDictionary rather than HashSet just for the concurrency security.
                var inverseGraph = new ConcurrentDictionary <ISymbol, ConcurrentDictionary <ISymbol, bool> >();

                // Ignore cases where a global anti forgery filter is in use.
                var hasGlobalAntiForgeryFilter = false;

                // Verify that validate anti forgery token attributes are used somewhere within this project,
                // to avoid reporting false positives on projects that use an alternative approach to mitigate CSRF issues.
                var usingValidateAntiForgeryAttribute = false;
                var onAuthorizationAsyncMethodSymbols = new HashSet <IMethodSymbol>();
                var actionMethodSymbols = new HashSet <(IMethodSymbol, string)>();
                var actionMethodNeedAddingHttpVerbAttributeSymbols = new HashSet <IMethodSymbol>();

                // Constructing inverse callGraph.
                // When it comes to delegate function assignment Del handler = DelegateMethod;, inverse call Graph will add:
                // (1) key: method gets called in DelegateMethod, value: handler.
                // When it comes to calling delegate function handler(), inverse callGraph will add:
                // (1) key: delegate function handler, value: callerMethod.
                // (2) key: Invoke(), value: callerMethod.
                compilationStartAnalysisContext.RegisterOperationBlockStartAction(
                    (OperationBlockStartAnalysisContext operationBlockStartAnalysisContext) =>
                {
                    if (hasGlobalAntiForgeryFilter)
                    {
                        return;
                    }

                    var owningSymbol = operationBlockStartAnalysisContext.OwningSymbol;
                    inverseGraph.GetOrAdd(owningSymbol, (_) => new ConcurrentDictionary <ISymbol, bool>());

                    operationBlockStartAnalysisContext.RegisterOperationAction(operationContext =>
                    {
                        ISymbol calledSymbol = null;
                        ConcurrentDictionary <ISymbol, bool> callers = null;

                        switch (operationContext.Operation)
                        {
                        case IInvocationOperation invocationOperation:
                            calledSymbol = invocationOperation.TargetMethod.OriginalDefinition;

                            break;

                        case IFieldReferenceOperation fieldReferenceOperation:
                            var fieldSymbol = (IFieldSymbol)fieldReferenceOperation.Field;

                            if (fieldSymbol.Type.TypeKind == TypeKind.Delegate)
                            {
                                calledSymbol = fieldSymbol;

                                break;
                            }

                            return;
                        }

                        if (calledSymbol == null)
                        {
                            return;
                        }

                        callers = inverseGraph.GetOrAdd(calledSymbol, (_) => new ConcurrentDictionary <ISymbol, bool>());
                        callers.TryAdd(owningSymbol, true);
                    }, OperationKind.Invocation, OperationKind.FieldReference);
                });

                // Holds if the project has a global anti forgery filter.
                compilationStartAnalysisContext.RegisterOperationAction(operationAnalysisContext =>
                {
                    if (hasGlobalAntiForgeryFilter)
                    {
                        return;
                    }

                    var invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation;
                    var methodSymbol        = invocationOperation.TargetMethod;

                    if (methodSymbol.Name == "Add" &&
                        methodSymbol.ContainingType.GetBaseTypesAndThis().Contains(filterCollectionTypeSymbol))
                    {
                        var potentialAntiForgeryFilters = invocationOperation
                                                          .Arguments
                                                          .Where(s => s.Parameter.Name == "filterType")
                                                          .Select(s => s.Value)
                                                          .OfType <ITypeOfOperation>()
                                                          .Select(s => s.TypeOperand)
                                                          .Union(methodSymbol.TypeArguments);

                        foreach (var potentialAntiForgeryFilter in potentialAntiForgeryFilters)
                        {
                            if (potentialAntiForgeryFilter.AllInterfaces.Contains(iFilterMetadataTypeSymbol) &&
                                s_AntiForgeryRegex.IsMatch(potentialAntiForgeryFilter.Name))
                            {
                                hasGlobalAntiForgeryFilter = true;

                                return;
                            }
                            else if (potentialAntiForgeryFilter.AllInterfaces.Contains(iAsyncAuthorizationFilterTypeSymbol) ||
                                     potentialAntiForgeryFilter.AllInterfaces.Contains(iAuthorizationFilterTypeSymbol))
                            {
                                onAuthorizationAsyncMethodSymbols.Add(
                                    potentialAntiForgeryFilter
                                    .GetMembers()
                                    .OfType <IMethodSymbol>()
                                    .FirstOrDefault(
                                        s => (s.Name == "OnAuthorizationAsync" ||
                                              s.Name == "OnAuthorization") &&
                                        s.ReturnType.Equals(taskTypeSymbol) &&
                                        s.Parameters.Length == 1 &&
                                        s.Parameters[0].Type.Equals(authorizationFilterContextTypeSymbol)));
                            }
                        }
                    }
                }, OperationKind.Invocation);

                compilationStartAnalysisContext.RegisterSymbolAction(symbolAnalysisContext =>
                {
                    if (hasGlobalAntiForgeryFilter)
                    {
                        return;
                    }

                    var derivedControllerTypeSymbol = (INamedTypeSymbol)symbolAnalysisContext.Symbol;
                    var baseTypes = derivedControllerTypeSymbol.GetBaseTypes();

                    // An subtype of `Microsoft.AspNetCore.Mvc.Controller` or `Microsoft.AspNetCore.Mvc.ControllerBase`).
                    if (baseTypes.Contains(controllerTypeSymbol) ||
                        baseTypes.Contains(controllerBaseTypeSymbol))
                    {
                        // The controller class is not protected by a validate anti forgery token attribute.
                        if (!IsUsingAntiFogeryAttribute(derivedControllerTypeSymbol))
                        {
                            foreach (var actionMethodSymbol in derivedControllerTypeSymbol.GetMembers().OfType <IMethodSymbol>())
                            {
                                if (actionMethodSymbol.MethodKind == MethodKind.Constructor)
                                {
                                    continue;
                                }

                                if (actionMethodSymbol.IsPublic() &&
                                    !actionMethodSymbol.IsStatic)
                                {
                                    var hasNonActionAttribute = actionMethodSymbol.HasAttribute(nonActionAttributeTypeSymbol);
                                    var overridenMethodSymbol = actionMethodSymbol as ISymbol;

                                    while (!hasNonActionAttribute && overridenMethodSymbol.IsOverride)
                                    {
                                        overridenMethodSymbol = overridenMethodSymbol.GetOverriddenMember();

                                        if (overridenMethodSymbol.HasAttribute(nonActionAttributeTypeSymbol))
                                        {
                                            hasNonActionAttribute = true;
                                        }
                                    }

                                    // The method has [NonAction].
                                    if (hasNonActionAttribute)
                                    {
                                        continue;
                                    }

                                    // The method is not protected by a validate anti forgery token attribute.
                                    if (!IsUsingAntiFogeryAttribute(actionMethodSymbol))
                                    {
                                        var httpVerbAttributeTypeSymbolAbleToModify = actionMethodSymbol.GetAttributes().FirstOrDefault(s => httpVerbAttributeTypeSymbolsAbleToModify.Contains(s.AttributeClass));

                                        if (httpVerbAttributeTypeSymbolAbleToModify != null)
                                        {
                                            var attributeName = httpVerbAttributeTypeSymbolAbleToModify.AttributeClass.Name;
                                            actionMethodSymbols.Add(
                                                (actionMethodSymbol,
                                                 attributeName.EndsWith("Attribute", StringComparison.Ordinal) ? attributeName.Remove(attributeName.Length - "Attribute".Length) : attributeName));
                                        }
                                        else if (!actionMethodSymbol.GetAttributes().Any(s => s.AttributeClass.GetBaseTypes().Contains(httpMethodAttributeTypeSymbol)))
                                        {
                                            actionMethodNeedAddingHttpVerbAttributeSymbols.Add((actionMethodSymbol));
                                        }
                                    }
                                }
                            }
                        }
                    }
                }, SymbolKind.NamedType);

                compilationStartAnalysisContext.RegisterCompilationEndAction(
                    (CompilationAnalysisContext compilationAnalysisContext) =>
                {
                    if (usingValidateAntiForgeryAttribute && !hasGlobalAntiForgeryFilter && (actionMethodSymbols.Any() || actionMethodNeedAddingHttpVerbAttributeSymbols.Any()))
                    {
                        var visited = new HashSet <ISymbol>();
                        var results = new Dictionary <ISymbol, HashSet <ISymbol> >();

                        if (onAuthorizationAsyncMethodSymbols.Any())
                        {
                            foreach (var calleeMethod in inverseGraph.Keys)
                            {
                                if (calleeMethod.Name == "ValidateRequestAsync" &&
                                    (calleeMethod.ContainingType.AllInterfaces.Contains(iAntiforgeryTypeSymbol) ||
                                     calleeMethod.ContainingType.Equals(iAntiforgeryTypeSymbol)))
                                {
                                    FindAllTheSpecifiedCalleeMethods(calleeMethod, visited, results);

                                    if (results.Values.Any(s => s.Any()))
                                    {
                                        return;
                                    }
                                }
                            }
                        }

                        foreach (var(methodSymbol, attributeName) in actionMethodSymbols)
                        {
                            compilationAnalysisContext.ReportDiagnostic(
                                methodSymbol.CreateDiagnostic(
                                    UseAutoValidateAntiforgeryTokenRule,
                                    methodSymbol.Name,
                                    attributeName));
                        }

                        foreach (var methodSymbol in actionMethodNeedAddingHttpVerbAttributeSymbols)
                        {
                            compilationAnalysisContext.ReportDiagnostic(
                                methodSymbol.CreateDiagnostic(
                                    MissHttpVerbAttributeRule,
                                    methodSymbol.Name));
                        }
                    }
                });

                // <summary>
                // Analyze the method to find all the specified methods that call it, in this case, the specified method symbols are in onAuthorizationAsyncMethodSymbols.
                // </summary>
                // <param name="methodSymbol">The symbol of the method to be analyzed</param>
                // <param name="visited">All the method has been analyzed</param>
                // <param name="results">The result is organized by &lt;method to be analyzed, specified methods calling it&gt;</param>
                void FindAllTheSpecifiedCalleeMethods(ISymbol methodSymbol, HashSet <ISymbol> visited, Dictionary <ISymbol, HashSet <ISymbol> > results)
                {
                    if (visited.Add(methodSymbol))
                    {
                        results.Add(methodSymbol, new HashSet <ISymbol>());

                        if (!inverseGraph.TryGetValue(methodSymbol, out var callingMethods))
                        {
                            Debug.Fail(methodSymbol.Name + " was not found in inverseGraph.");

                            return;
                        }

                        foreach (var child in callingMethods.Keys)
                        {
                            if (onAuthorizationAsyncMethodSymbols.Contains(child))
                            {
                                results[methodSymbol].Add(child);
                            }

                            FindAllTheSpecifiedCalleeMethods(child, visited, results);

                            if (results.TryGetValue(child, out var result))
                            {
                                results[methodSymbol].UnionWith(result);
                            }
                            else
                            {
                                Debug.Fail(child.Name + " was not found in results.");
                            }
                        }
                    }
                }

                bool IsUsingAntiFogeryAttribute(ISymbol symbol)
                {
                    if (symbol.GetAttributes().Any(s => s_AntiForgeryAttributeRegex.IsMatch(s.AttributeClass.Name)))
                    {
                        usingValidateAntiForgeryAttribute = true;

                        return(true);
                    }
                    else
                    {
                        return(false);
                    }
                }
            });
        }