public TaintedDataSymbolMap(WellKnownTypeProvider wellKnownTypeProvider, IEnumerable <TInfo> taintedDataInfos) { if (wellKnownTypeProvider == null) { throw new ArgumentNullException(nameof(wellKnownTypeProvider)); } if (taintedDataInfos == null) { throw new ArgumentNullException(nameof(taintedDataInfos)); } ImmutableDictionary <ITypeSymbol, TInfo> .Builder concreteInfosBuilder = ImmutableDictionary.CreateBuilder <ITypeSymbol, TInfo>(); ImmutableDictionary <ITypeSymbol, TInfo> .Builder interfaceInfosBuilder = ImmutableDictionary.CreateBuilder <ITypeSymbol, TInfo>(); foreach (TInfo info in taintedDataInfos) { if (wellKnownTypeProvider.TryGetTypeByMetadataName(info.FullTypeName, out INamedTypeSymbol namedTypeSymbol)) { if (info.IsInterface) { interfaceInfosBuilder[namedTypeSymbol] = info; } else { concreteInfosBuilder[namedTypeSymbol] = info; } } } this.ConcreteInfos = concreteInfosBuilder.ToImmutable(); this.InterfaceInfos = interfaceInfosBuilder.ToImmutable(); }
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) => { ConcurrentDictionary <IMethodSymbol, CacheState> methodCache = new ConcurrentDictionary <IMethodSymbol, CacheState>(); WellKnownTypeProvider typeProvider = WellKnownTypeProvider.GetOrCreate(compilationStartAnalysisContext.Compilation); INamedTypeSymbol serializationBinder = null; if (!typeProvider.TryGetTypeByMetadataName(WellKnownTypeNames.SystemRuntimeSerializationSerializationBinder, out serializationBinder)) { return; } compilationStartAnalysisContext.RegisterSymbolAction( (SymbolAnalysisContext symbolAnalysisContext) => { IMethodSymbol msym = (IMethodSymbol)symbolAnalysisContext.Symbol; if (msym.Name == "BindToType") { if (msym.ContainingType.Inherits(serializationBinder)) { IBlockOperation msymOps = msym.GetTopmostOperationBlock(compilationStartAnalysisContext.Compilation); methodCache[msym] = CacheState.InProgress; if (!hasThrow(msymOps.Operations)) { methodCache[msym] = CacheState.PresentTrue; symbolAnalysisContext.ReportDiagnostic( Diagnostic.Create( DoNotOverloadSerializationBinderWithoutThrowingAnExceptionRule, msym.Locations[0], msym.ContainingType.ToDisplayString( SymbolDisplayFormat.MinimallyQualifiedFormat))); } else { methodCache[msym] = CacheState.PresentFalse; } } } } , SymbolKind.Method); bool hasThrow(IEnumerable <Microsoft.CodeAnalysis.IOperation> ops) { if (ops == null) { //doesn't happen, but just in case Debug.Fail("hasThrow called on null value. It should be called on an IEnumerable of IOperations."); return(false); } foreach (IOperation op in ops) { if (op == null) { continue; } if (op.Kind == OperationKind.Invocation) { IMethodSymbol func = ((IInvocationOperation)op).TargetMethod; CacheState methodState; if (!methodCache.TryGetValue(func, out methodState)) { methodState = CacheState.Absent; } if (methodState == CacheState.PresentTrue) { return(true); //we've done this before } if (methodState == CacheState.PresentFalse) { continue; //no need to go here again } if (methodState == CacheState.InProgress) { continue; //avoid recursive functions causing a loop } methodCache[func] = CacheState.InProgress; IBlockOperation funcOps = func.GetTopmostOperationBlock(compilationStartAnalysisContext.Compilation); if (funcOps == null) { //function's source is in another assembly, and we cannot scan it //we will assume in this case that, even if this function throws an exception, it's probably not one we care about methodCache[func] = CacheState.PresentFalse; continue; } if (hasThrow(funcOps.Operations)) { methodCache[func] = CacheState.PresentTrue; return(true); } } if (op.Kind == OperationKind.Throw) { return(true); } if (hasThrow(op.Descendants())) { return(true); } } return(false); } } ); }
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) => { WellKnownTypeProvider wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilationStartAnalysisContext.Compilation); if (!wellKnownTypeProvider.TryGetTypeByMetadataName(WellKnownTypeNames.SystemWebHttpCookie, out INamedTypeSymbol httpCookieSymbol)) { return; } PooledHashSet <(IOperation Operation, ISymbol ContainingSymbol)> rootOperationsNeedingAnalysis = PooledHashSet <(IOperation, ISymbol)> .GetInstance(); compilationStartAnalysisContext.RegisterOperationBlockStartAction( (OperationBlockStartAnalysisContext operationBlockStartAnalysisContext) => { ISymbol owningSymbol = operationBlockStartAnalysisContext.OwningSymbol; if (owningSymbol.IsConfiguredToSkipAnalysis( operationBlockStartAnalysisContext.Options, Rule, operationBlockStartAnalysisContext.Compilation, operationBlockStartAnalysisContext.CancellationToken)) { return; } operationBlockStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { ISimpleAssignmentOperation simpleAssignmentOperation = (ISimpleAssignmentOperation)operationAnalysisContext.Operation; if (simpleAssignmentOperation.Target is IPropertyReferenceOperation propertyReferenceOperation && httpCookieSymbol.Equals(propertyReferenceOperation.Property.ContainingType) && propertyReferenceOperation.Property.Name == "HttpOnly" && simpleAssignmentOperation.Value.ConstantValue.HasValue && simpleAssignmentOperation.Value.ConstantValue.Value.Equals(false)) { operationAnalysisContext.ReportDiagnostic( simpleAssignmentOperation.CreateDiagnostic( Rule)); } }, OperationKind.SimpleAssignment); operationBlockStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { IReturnOperation returnOperation = (IReturnOperation)operationAnalysisContext.Operation; if (httpCookieSymbol.Equals(returnOperation.ReturnedValue?.Type)) { lock (rootOperationsNeedingAnalysis) { rootOperationsNeedingAnalysis.Add( (returnOperation.GetRoot(), operationAnalysisContext.ContainingSymbol)); } } }, OperationKind.Return); operationBlockStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { IArgumentOperation argumentOperation = (IArgumentOperation)operationAnalysisContext.Operation; if (httpCookieSymbol.Equals(argumentOperation.Value.Type)) { lock (rootOperationsNeedingAnalysis) { rootOperationsNeedingAnalysis.Add( (argumentOperation.GetRoot(), operationAnalysisContext.ContainingSymbol)); } } }, OperationKind.Argument); }); compilationStartAnalysisContext.RegisterCompilationEndAction( (CompilationAnalysisContext compilationAnalysisContext) => { PooledDictionary <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> allResults = null; try { lock (rootOperationsNeedingAnalysis) { if (!rootOperationsNeedingAnalysis.Any()) { return; } allResults = PropertySetAnalysis.BatchGetOrComputeHazardousUsages( compilationAnalysisContext.Compilation, rootOperationsNeedingAnalysis, compilationAnalysisContext.Options, WellKnownTypeNames.SystemWebHttpCookie, ConstructorMapper, PropertyMappers, HazardousUsageEvaluators, InterproceduralAnalysisConfiguration.Create( compilationAnalysisContext.Options, SupportedDiagnostics, defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.ContextSensitive, cancellationToken: compilationAnalysisContext.CancellationToken)); } if (allResults == null) { return; } foreach (KeyValuePair <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> kvp in allResults) { if (kvp.Value == HazardousUsageEvaluationResult.Flagged) { compilationAnalysisContext.ReportDiagnostic( Diagnostic.Create( Rule, kvp.Key.Location)); } } } finally { rootOperationsNeedingAnalysis.Free(); allResults?.Free(); } }); }); }
public override void Initialize(AnalysisContext analysisContext) { analysisContext.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.ReportDiagnostics); analysisContext.EnableConcurrentExecution(); analysisContext.RegisterCompilationStartAction( (CompilationStartAnalysisContext compilationStartAnalysisContext) => { WellKnownTypeProvider wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate( compilationStartAnalysisContext.Compilation); if (!wellKnownTypeProvider.TryGetTypeByMetadataName( WellKnownTypeNames.NewtonsoftJsonTypeNameHandling, out INamedTypeSymbol typeNameHandlingSymbol)) { return; } compilationStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { IFieldReferenceOperation fieldReferenceOperation = (IFieldReferenceOperation)operationAnalysisContext.Operation; if (IsOtherThanNone(fieldReferenceOperation)) { operationAnalysisContext.ReportDiagnostic( fieldReferenceOperation.CreateDiagnostic(Rule)); } }, OperationKind.FieldReference); compilationStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { IAssignmentOperation assignmentOperation = (IAssignmentOperation)operationAnalysisContext.Operation; if (!typeNameHandlingSymbol.Equals(assignmentOperation.Target.Type)) { return; } // Find the topmost operation with non-zero (not None), unless we find an operation that would've // been flagged by the FieldReference callback above. foreach (IOperation childOperation in assignmentOperation.Value.DescendantsAndSelf()) { if (childOperation is IFieldReferenceOperation fieldReferenceOperation && IsOtherThanNone(fieldReferenceOperation)) { return; } if (childOperation.ConstantValue.HasValue && childOperation.ConstantValue.Value is int integerValue && integerValue != 0) { operationAnalysisContext.ReportDiagnostic(childOperation.CreateDiagnostic(Rule)); return; } } }, OperationKind.SimpleAssignment, OperationKind.CompoundAssignment); return; bool IsOtherThanNone(IFieldReferenceOperation fieldReferenceOperation) { if (!typeNameHandlingSymbol.Equals(fieldReferenceOperation.Field.ContainingType)) { return(false); } return(fieldReferenceOperation.Field.Name != "None"); }; }); }
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, PropertySetCallbacks.FlagIfNull)); HazardousUsageEvaluatorCollection hazardousUsageEvaluators = new HazardousUsageEvaluatorCollection( cachedDeserializationMethodNames.Select( methodName => new HazardousUsageEvaluator( methodName, PropertySetCallbacks.HazardousIfAllFlaggedOrAllUnknown))); 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) => { var owningSymbol = operationBlockStartAnalysisContext.OwningSymbol; // TODO: Handle case when exactly one of the below rules is configured to skip analysis. if (owningSymbol.IsConfiguredToSkipAnalysis(operationBlockStartAnalysisContext.Options, BinderDefinitelyNotSetDescriptor, operationBlockStartAnalysisContext.Compilation, operationBlockStartAnalysisContext.CancellationToken) && owningSymbol.IsConfiguredToSkipAnalysis(operationBlockStartAnalysisContext.Options, BinderMaybeNotSetDescriptor, operationBlockStartAnalysisContext.Compilation, operationBlockStartAnalysisContext.CancellationToken)) { return; } operationBlockStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { IObjectCreationOperation creationOperation = (IObjectCreationOperation)operationAnalysisContext.Operation; if (deserializerTypeSymbol.Equals(creationOperation.Type)) { lock (rootOperationsNeedingAnalysis) { rootOperationsNeedingAnalysis.Add((operationAnalysisContext.Operation.GetRoot(), operationAnalysisContext.ContainingSymbol)); } } }, OperationKind.ObjectCreation); operationBlockStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { IInvocationOperation invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation; if (Equals(invocationOperation.Instance?.Type, deserializerTypeSymbol) && cachedDeserializationMethodNames.Contains(invocationOperation.TargetMethod.Name)) { lock (rootOperationsNeedingAnalysis) { rootOperationsNeedingAnalysis.Add((operationAnalysisContext.Operation.GetRoot(), operationAnalysisContext.ContainingSymbol)); } } }, OperationKind.Invocation); operationBlockStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { IMethodReferenceOperation methodReferenceOperation = (IMethodReferenceOperation)operationAnalysisContext.Operation; if (Equals(methodReferenceOperation.Instance?.Type, deserializerTypeSymbol) && cachedDeserializationMethodNames.Contains( methodReferenceOperation.Method.MetadataName)) { lock (rootOperationsNeedingAnalysis) { rootOperationsNeedingAnalysis.Add((operationAnalysisContext.Operation.GetRoot(), operationAnalysisContext.ContainingSymbol)); } } }, OperationKind.MethodReference); }); compilationStartAnalysisContext.RegisterCompilationEndAction( (CompilationAnalysisContext compilationAnalysisContext) => { PooledDictionary <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> allResults = null; try { lock (rootOperationsNeedingAnalysis) { if (!rootOperationsNeedingAnalysis.Any()) { return; } allResults = PropertySetAnalysis.BatchGetOrComputeHazardousUsages( compilationAnalysisContext.Compilation, rootOperationsNeedingAnalysis, compilationAnalysisContext.Options, this.DeserializerTypeMetadataName, DoNotUseInsecureDeserializerWithoutBinderBase.ConstructorMapper, propertyMappers, hazardousUsageEvaluators, InterproceduralAnalysisConfiguration.Create( compilationAnalysisContext.Options, SupportedDiagnostics, 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(); // Security analyzer - analyze and report diagnostics on generated code. context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); HazardousUsageEvaluatorCollection hazardousUsageEvaluators = new HazardousUsageEvaluatorCollection( SecurityHelpers.JavaScriptSerializerDeserializationMethods.Select( (string methodName) => new HazardousUsageEvaluator(methodName, HazardousUsageCallback))); context.RegisterCompilationStartAction( (CompilationStartAnalysisContext compilationStartAnalysisContext) => { WellKnownTypeProvider wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilationStartAnalysisContext.Compilation); if (!wellKnownTypeProvider.TryGetTypeByMetadataName(WellKnownTypeNames.SystemWebScriptSerializationJavaScriptSerializer, out INamedTypeSymbol javaScriptSerializerSymbol) || !wellKnownTypeProvider.TryGetTypeByMetadataName(WellKnownTypeNames.SystemWebScriptSerializationJavaScriptTypeResolver, out INamedTypeSymbol javaScriptTypeResolverSymbol) || !wellKnownTypeProvider.TryGetTypeByMetadataName(WellKnownTypeNames.SystemWebScriptSerializationSimpleTypeResolver, out INamedTypeSymbol simpleTypeResolverSymbol)) { return; } // If JavaScriptSerializer is initialized with a SimpleTypeResolver, then that instance is flagged. ConstructorMapper constructorMapper = new ConstructorMapper( (IMethodSymbol constructorMethod, IReadOnlyList <PointsToAbstractValue> argumentPointsToAbstractValues) => { PropertySetAbstractValueKind kind; if (constructorMethod.Parameters.Length == 0) { kind = PropertySetAbstractValueKind.Unflagged; } else if (constructorMethod.Parameters.Length == 1 && javaScriptTypeResolverSymbol.Equals(constructorMethod.Parameters[0].Type)) { PointsToAbstractValue pointsTo = argumentPointsToAbstractValues[0]; switch (pointsTo.Kind) { case PointsToAbstractValueKind.Invalid: case PointsToAbstractValueKind.UnknownNull: case PointsToAbstractValueKind.Undefined: kind = PropertySetAbstractValueKind.Unflagged; break; case PointsToAbstractValueKind.KnownLocations: if (pointsTo.Locations.Any(l => !l.IsNull && simpleTypeResolverSymbol.Equals(l.LocationTypeOpt))) { kind = PropertySetAbstractValueKind.Flagged; } else if (pointsTo.Locations.Any(l => !l.IsNull && javaScriptTypeResolverSymbol.Equals(l.LocationTypeOpt) && (l.CreationOpt == null || l.CreationOpt.Kind != OperationKind.ObjectCreation))) { // Points to a JavaScriptTypeResolver, but we don't know if the instance is a SimpleTypeResolver. kind = PropertySetAbstractValueKind.MaybeFlagged; } else { kind = PropertySetAbstractValueKind.Unflagged; } break; case PointsToAbstractValueKind.UnknownNotNull: case PointsToAbstractValueKind.Unknown: kind = PropertySetAbstractValueKind.MaybeFlagged; break; default: Debug.Fail($"Unhandled PointsToAbstractValueKind {pointsTo.Kind}"); kind = PropertySetAbstractValueKind.Unflagged; break; } } else { Debug.Fail($"Unhandled JavaScriptSerializer constructor {constructorMethod.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat)}"); kind = PropertySetAbstractValueKind.Unflagged; } return(PropertySetAbstractValue.GetInstance(kind)); }); PooledHashSet <(IOperation Operation, ISymbol ContainingSymbol)> rootOperationsNeedingAnalysis = PooledHashSet <(IOperation, ISymbol)> .GetInstance(); compilationStartAnalysisContext.RegisterOperationBlockStartAction( (OperationBlockStartAnalysisContext operationBlockStartAnalysisContext) => { operationBlockStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { IInvocationOperation invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation; if ((javaScriptSerializerSymbol.Equals(invocationOperation.Instance?.Type) && SecurityHelpers.JavaScriptSerializerDeserializationMethods.Contains(invocationOperation.TargetMethod.Name)) || simpleTypeResolverSymbol.Equals(invocationOperation.TargetMethod.ReturnType) || javaScriptTypeResolverSymbol.Equals(invocationOperation.TargetMethod.ReturnType)) { lock (rootOperationsNeedingAnalysis) { rootOperationsNeedingAnalysis.Add((invocationOperation.GetRoot(), operationAnalysisContext.ContainingSymbol)); } } }, OperationKind.Invocation); operationBlockStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { IMethodReferenceOperation methodReferenceOperation = (IMethodReferenceOperation)operationAnalysisContext.Operation; if (javaScriptSerializerSymbol.Equals(methodReferenceOperation.Instance?.Type) && SecurityHelpers.JavaScriptSerializerDeserializationMethods.Contains(methodReferenceOperation.Method.Name)) { lock (rootOperationsNeedingAnalysis) { rootOperationsNeedingAnalysis.Add((operationAnalysisContext.Operation.GetRoot(), operationAnalysisContext.ContainingSymbol)); } } }, OperationKind.MethodReference); }); compilationStartAnalysisContext.RegisterCompilationEndAction( (CompilationAnalysisContext compilationAnalysisContext) => { PooledDictionary <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> allResults = null; try { lock (rootOperationsNeedingAnalysis) { if (!rootOperationsNeedingAnalysis.Any()) { return; } allResults = PropertySetAnalysis.BatchGetOrComputeHazardousUsages( compilationAnalysisContext.Compilation, rootOperationsNeedingAnalysis, WellKnownTypeNames.SystemWebScriptSerializationJavaScriptSerializer, constructorMapper, PropertyMappers, hazardousUsageEvaluators, InterproceduralAnalysisConfiguration.Create( compilationAnalysisContext.Options, SupportedDiagnostics, defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.ContextSensitive, cancellationToken: compilationAnalysisContext.CancellationToken)); } if (allResults == null) { return; } foreach (KeyValuePair <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> kvp in allResults) { DiagnosticDescriptor descriptor; switch (kvp.Value) { case HazardousUsageEvaluationResult.Flagged: descriptor = DefinitelyWithSimpleTypeResolver; break; case HazardousUsageEvaluationResult.MaybeFlagged: descriptor = MaybeWithSimpleTypeResolver; break; default: Debug.Fail($"Unhandled result value {kvp.Value}"); continue; } compilationAnalysisContext.ReportDiagnostic( Diagnostic.Create( descriptor, kvp.Key.Location, kvp.Key.Method.ToDisplayString( SymbolDisplayFormat.MinimallyQualifiedFormat))); } } finally { rootOperationsNeedingAnalysis.Free(); allResults?.Free(); } }); }); }
public 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) => { WellKnownTypeProvider wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilationStartAnalysisContext.Compilation); if (!wellKnownTypeProvider.TryGetTypeByMetadataName( WellKnownTypeNames.SystemSecurityAuthenticationSslProtocols, out INamedTypeSymbol sslProtocolsSymbol)) { return; } compilationStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { IFieldReferenceOperation fieldReferenceOperation = (IFieldReferenceOperation)operationAnalysisContext.Operation; if (IsReferencingSslProtocols( fieldReferenceOperation, out bool isDeprecatedProtocol, out bool isHardcodedOkayProtocol)) { 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) => { IOperation valueOperation; switch (operationAnalysisContext.Operation) { case IAssignmentOperation assignmentOperation: // Make sure this is an assignment operation for a SslProtocols value. if (!sslProtocolsSymbol.Equals(assignmentOperation.Target.Type)) { return; } valueOperation = assignmentOperation.Value; break; case IArgumentOperation argumentOperation: if (!sslProtocolsSymbol.Equals(argumentOperation.Type)) { return; } valueOperation = argumentOperation.Value; break; case IReturnOperation returnOperation: if (returnOperation.ReturnedValue == null || !sslProtocolsSymbol.Equals(returnOperation.ReturnedValue.Type)) { return; } valueOperation = returnOperation.ReturnedValue; break; case IVariableInitializerOperation variableInitializerOperation: if (variableInitializerOperation.Value != null && !sslProtocolsSymbol.Equals(variableInitializerOperation.Value.Type)) { return; } valueOperation = variableInitializerOperation.Value; break; default: Debug.Fail("Unhandled IOperation " + operationAnalysisContext.Operation.Kind); 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 valueOperation.DescendantsAndSelf()) { if (childOperation is IFieldReferenceOperation fieldReferenceOperation && IsReferencingSslProtocols( 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, OperationKind.Argument, OperationKind.Return, OperationKind.VariableInitializer); return; // Local function(s). bool IsReferencingSslProtocols( IFieldReferenceOperation fieldReferenceOperation, out bool isDeprecatedProtocol, out bool isHardcodedOkayProtocol) { if (sslProtocolsSymbol.Equals(fieldReferenceOperation.Field.ContainingType)) { if (HardcodedSslProtocolsMetadataNames.Contains(fieldReferenceOperation.Field.Name)) { isHardcodedOkayProtocol = true; isDeprecatedProtocol = false; } else if (fieldReferenceOperation.Field.Name == "None") { isHardcodedOkayProtocol = false; isDeprecatedProtocol = false; } else { isDeprecatedProtocol = true; isHardcodedOkayProtocol = false; } return(true); } else { isHardcodedOkayProtocol = false; isDeprecatedProtocol = false; return(false); } } }); }
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, (NullAbstractValue nullAbstractValue) => { // A null SerializationBinder is what we want to flag as hazardous. switch (nullAbstractValue) { 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; } compilationStartAnalysisContext.RegisterOperationBlockStartAction( (OperationBlockStartAnalysisContext operationBlockStartAnalysisContext) => { PooledHashSet <IOperation> rootOperationsNeedingAnalysis = PooledHashSet <IOperation> .GetInstance(); operationBlockStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { IInvocationOperation invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation; if (invocationOperation.Instance?.Type == deserializerTypeSymbol && cachedDeserializationMethodNames.Contains(invocationOperation.TargetMethod.Name)) { lock (rootOperationsNeedingAnalysis) { rootOperationsNeedingAnalysis.Add(operationAnalysisContext.Operation.GetRoot()); } } }, OperationKind.Invocation); operationBlockStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { IMethodReferenceOperation methodReferenceOperation = (IMethodReferenceOperation)operationAnalysisContext.Operation; if (methodReferenceOperation.Instance?.Type == deserializerTypeSymbol && cachedDeserializationMethodNames.Contains( methodReferenceOperation.Method.MetadataName)) { lock (rootOperationsNeedingAnalysis) { rootOperationsNeedingAnalysis.Add(operationAnalysisContext.Operation.GetRoot()); } } }, OperationKind.MethodReference); operationBlockStartAnalysisContext.RegisterOperationBlockEndAction( (OperationBlockAnalysisContext operationBlockAnalysisContext) => { PooledDictionary <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> allResults = null; try { lock (rootOperationsNeedingAnalysis) { if (!rootOperationsNeedingAnalysis.Any()) { return; } // Only instantiated if there are any results to report. List <ControlFlowGraph> cfgs = new List <ControlFlowGraph>(); var interproceduralAnalysisConfig = InterproceduralAnalysisConfiguration.Create( operationBlockAnalysisContext.Options, SupportedDiagnostics, defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.None, cancellationToken: operationBlockAnalysisContext.CancellationToken, defaultMaxInterproceduralMethodCallChain: 1); // By default, we only want to track method calls one level down. foreach (IOperation rootOperation in rootOperationsNeedingAnalysis) { ImmutableDictionary <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> dfaResult = PropertySetAnalysis.GetOrComputeHazardousUsages( rootOperation.GetEnclosingControlFlowGraph(), operationBlockAnalysisContext.Compilation, operationBlockAnalysisContext.OwningSymbol, this.DeserializerTypeMetadataName, DoNotUseInsecureDeserializerWithoutBinderBase.ConstructorMapper, propertyMappers, hazardousUsageEvaluators, interproceduralAnalysisConfig); if (dfaResult.IsEmpty) { continue; } if (allResults == null) { allResults = PooledDictionary <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> .GetInstance(); } foreach (KeyValuePair <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> kvp in dfaResult) { allResults.Add(kvp.Key, kvp.Value); } } } 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; } operationBlockAnalysisContext.ReportDiagnostic( Diagnostic.Create( descriptor, kvp.Key.Location, kvp.Key.Method.ToDisplayString( SymbolDisplayFormat.MinimallyQualifiedFormat))); } } finally { rootOperationsNeedingAnalysis.Free(); allResults?.Free(); } }); }); }); }