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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                        if (allResults == null)
                        {
                            return;
                        }

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

                            case HazardousUsageEvaluationResult.MaybeFlagged:
                                descriptor = MaybeUseWeakKDFInsufficientIterationCountRule;
                                break;

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

                            compilationAnalysisContext.ReportDiagnostic(
                                Diagnostic.Create(
                                    descriptor,
                                    kvp.Key.Location,
                                    sufficientIterationCount));
                        }
                    }
                    finally
                    {
                        rootOperationsNeedingAnalysis.Free();
                        allResults?.Free();
                    }
                });
            });
        }
 private static HazardousUsageEvaluationResult HazardousUsageCallback(IMethodSymbol methodSymbol, PropertySetAbstractValue propertySetAbstractValue)
 {
     return((propertySetAbstractValue[0]) switch
     {
         PropertySetAbstractValueKind.Flagged => HazardousUsageEvaluationResult.Flagged,
         PropertySetAbstractValueKind.Unflagged => HazardousUsageEvaluationResult.Unflagged,
         _ => HazardousUsageEvaluationResult.MaybeFlagged,
     });
        private static HazardousUsageEvaluationResult HazardousUsageCallback(IMethodSymbol methodSymbol, PropertySetAbstractValue propertySetAbstractValue)
        {
            switch (propertySetAbstractValue[0])
            {
            case PropertySetAbstractValueKind.Flagged:
                return(HazardousUsageEvaluationResult.Flagged);

            case PropertySetAbstractValueKind.MaybeFlagged:
                return(HazardousUsageEvaluationResult.MaybeFlagged);

            default:
                return(HazardousUsageEvaluationResult.Unflagged);
            }
        }
        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>
        /// For PropertySetAnalysis dataflow analysis; hazardous usage evaluation callback.
        /// </summary>
        /// <param name="methodSymbol"></param>
        /// <param name="propertySetAbstractValue"></param>
        /// <returns></returns>
        private static HazardousUsageEvaluationResult HazardousIfNull(IMethodSymbol methodSymbol, PropertySetAbstractValue propertySetAbstractValue)
        {
            switch (propertySetAbstractValue[SerializationBinderIndex])
            {
            case PropertySetAbstractValueKind.Flagged:
                return(HazardousUsageEvaluationResult.Flagged);

            case PropertySetAbstractValueKind.Unflagged:
                return(HazardousUsageEvaluationResult.Unflagged);

            default:
                return(HazardousUsageEvaluationResult.MaybeFlagged);
            }
        }
示例#6
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();
                    }
                });
            });
        }
        private static HazardousUsageEvaluationResult PropertiesCountEvaluatorCallback(PropertySetAbstractValue abstractValue, int minCount, bool auditMode)
        {
            int maybe = 0;
            int no    = 0;

            for (int i = 0; i < abstractValue.KnownValuesCount; ++i)
            {
                switch (abstractValue[i])
                {
                case PropertySetAbstractValueKind.MaybeFlagged:
                    ++maybe;
                    break;

                case PropertySetAbstractValueKind.Unflagged:
                    ++no;
                    break;
                }
            }

            int count = no;

            if (!auditMode)
            {
                count += maybe;
            }

            if (count < minCount)
            {
                if (no == 0 && maybe > 0)
                {
                    return(HazardousUsageEvaluationResult.MaybeFlagged);
                }
                else
                {
                    return(HazardousUsageEvaluationResult.Flagged);
                }
            }
            else
            {
                return(HazardousUsageEvaluationResult.Unflagged);
            }
        }