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); }); }
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); }); }
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); }); }); }
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"); } }); }
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); }); }
public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); // Security analyzer - analyze and report diagnostics on generated code. context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); HazardousUsageEvaluatorCollection hazardousUsageEvaluators = new HazardousUsageEvaluatorCollection( new HazardousUsageEvaluator("Add", HazardousUsageCallback)); context.RegisterCompilationStartAction( (CompilationStartAnalysisContext compilationStartAnalysisContext) => { var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilationStartAnalysisContext.Compilation); if (!wellKnownTypeProvider.TryGetTypeByMetadataName(WellKnownTypeNames.SystemSecurityCryptographyX509CertificatesX509Store, out var x509TypeSymbol)) { return; } if (!wellKnownTypeProvider.TryGetTypeByMetadataName(WellKnownTypeNames.SystemSecurityCryptographyX509CertificatesStoreName, out var storeNameTypeSymbol)) { return; } // If X509Store is initialized with Root store, then that instance is flagged. var constructorMapper = new ConstructorMapper( (IMethodSymbol constructorMethod, IReadOnlyList <ValueContentAbstractValue> argumentValueContentAbstractValues, IReadOnlyList <PointsToAbstractValue> argumentPointsToAbstractValues) => { var kind = PropertySetAbstractValueKind.Unflagged; if (constructorMethod.Parameters.Length > 0) { if (constructorMethod.Parameters[0].Type.Equals(storeNameTypeSymbol)) { kind = PropertySetCallbacks.EvaluateLiteralValues(argumentValueContentAbstractValues[0], o => o.Equals(6)); } else if (constructorMethod.Parameters[0].Type.SpecialType == SpecialType.System_String) { kind = PropertySetCallbacks.EvaluateLiteralValues( argumentValueContentAbstractValues[0], s => string.Equals(s.ToString(), "root", StringComparison.OrdinalIgnoreCase)); } } return(PropertySetAbstractValue.GetInstance(kind)); }); var rootOperationsNeedingAnalysis = PooledHashSet <(IOperation, ISymbol)> .GetInstance(); compilationStartAnalysisContext.RegisterOperationBlockStartAction( (OperationBlockStartAnalysisContext operationBlockStartAnalysisContext) => { operationBlockStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { var invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation; if (x509TypeSymbol.Equals(invocationOperation.Instance?.Type) && invocationOperation.TargetMethod.Name == "Add") { lock (rootOperationsNeedingAnalysis) { rootOperationsNeedingAnalysis.Add((invocationOperation.GetRoot(), operationAnalysisContext.ContainingSymbol)); } } }, OperationKind.Invocation); operationBlockStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { var argumentOperation = (IArgumentOperation)operationAnalysisContext.Operation; if (x509TypeSymbol.Equals(argumentOperation.Parameter.Type)) { lock (rootOperationsNeedingAnalysis) { rootOperationsNeedingAnalysis.Add((argumentOperation.GetRoot(), operationAnalysisContext.ContainingSymbol)); } } }, OperationKind.Argument); }); compilationStartAnalysisContext.RegisterCompilationEndAction( (CompilationAnalysisContext compilationAnalysisContext) => { PooledDictionary <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> allResults = null; try { lock (rootOperationsNeedingAnalysis) { if (!rootOperationsNeedingAnalysis.Any()) { return; } allResults = PropertySetAnalysis.BatchGetOrComputeHazardousUsages( compilationAnalysisContext.Compilation, rootOperationsNeedingAnalysis, WellKnownTypeNames.SystemSecurityCryptographyX509CertificatesX509Store, constructorMapper, PropertyMappers, hazardousUsageEvaluators, InterproceduralAnalysisConfiguration.Create( compilationAnalysisContext.Options, SupportedDiagnostics, defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.ContextSensitive, cancellationToken: compilationAnalysisContext.CancellationToken)); } if (allResults == null) { return; } foreach (KeyValuePair <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> kvp in allResults) { DiagnosticDescriptor descriptor; switch (kvp.Value) { case HazardousUsageEvaluationResult.Flagged: descriptor = DefinitelyInstallRootCertRule; break; case HazardousUsageEvaluationResult.MaybeFlagged: descriptor = MaybeInstallRootCertRule; break; default: Debug.Fail($"Unhandled result value {kvp.Value}"); continue; } compilationAnalysisContext.ReportDiagnostic( Diagnostic.Create( descriptor, kvp.Key.Location, kvp.Key.Method.ToDisplayString( SymbolDisplayFormat.MinimallyQualifiedFormat))); } } finally { rootOperationsNeedingAnalysis.Free(); allResults?.Free(); } }); }); }
public 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)); }
internal static void AddCoupledNamedTypes(ImmutableHashSet <INamedTypeSymbol> .Builder builder, WellKnownTypeProvider wellKnownTypeProvider, ImmutableArray <IParameterSymbol> parameters) { foreach (var parameter in parameters) { AddCoupledNamedTypesCore(builder, parameter.Type, wellKnownTypeProvider); } }
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); } } } }); }); }
public AttributesAnalyzer(DiagnosticDescriptor rule, WellKnownTypeProvider wellKnownTypeProvider) { Rule = rule; WellKnownTypeProvider = wellKnownTypeProvider; }
public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); context.RegisterCompilationStartAction( (CompilationStartAnalysisContext compilationContext) => { TaintedDataConfig taintedDataConfig = TaintedDataConfig.GetOrCreate(compilationContext.Compilation); TaintedDataSymbolMap <SourceInfo> sourceInfoSymbolMap = taintedDataConfig.GetSourceSymbolMap(this.SinkKind); if (sourceInfoSymbolMap.IsEmpty) { return; } TaintedDataSymbolMap <SinkInfo> sinkInfoSymbolMap = taintedDataConfig.GetSinkSymbolMap(this.SinkKind); if (sinkInfoSymbolMap.IsEmpty) { return; } compilationContext.RegisterOperationBlockStartAction( operationBlockStartContext => { ISymbol owningSymbol = operationBlockStartContext.OwningSymbol; if (owningSymbol.IsConfiguredToSkipAnalysis(operationBlockStartContext.Options, TaintedDataEnteringSinkDescriptor, operationBlockStartContext.Compilation, operationBlockStartContext.CancellationToken)) { return; } PooledHashSet <IOperation> rootOperationsNeedingAnalysis = PooledHashSet <IOperation> .GetInstance(); operationBlockStartContext.RegisterOperationAction( operationAnalysisContext => { IPropertyReferenceOperation propertyReferenceOperation = (IPropertyReferenceOperation)operationAnalysisContext.Operation; IOperation rootOperation = operationAnalysisContext.Operation.GetRoot(); if (sourceInfoSymbolMap.IsSourceProperty(propertyReferenceOperation.Property)) { lock (rootOperationsNeedingAnalysis) { rootOperationsNeedingAnalysis.Add(rootOperation); } } }, OperationKind.PropertyReference); operationBlockStartContext.RegisterOperationAction( operationAnalysisContext => { IInvocationOperation invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation; IOperation rootOperation = operationAnalysisContext.Operation.GetRoot(); PooledDictionary <PointsToCheck, ImmutableHashSet <string> > evaluateWithPointsToAnalysis = null; PooledDictionary <ValueContentCheck, ImmutableHashSet <string> > evaluateWithValueContentAnalysis = null; PointsToAnalysisResult pointsToAnalysisResult = null; ValueContentAnalysisResult valueContentAnalysisResult = null; if (rootOperation.TryGetEnclosingControlFlowGraph(out ControlFlowGraph cfg)) { pointsToAnalysisResult = PointsToAnalysis.TryGetOrComputeResult( cfg, owningSymbol, operationAnalysisContext.Options, WellKnownTypeProvider.GetOrCreate(operationAnalysisContext.Compilation), InterproceduralAnalysisConfiguration.Create( operationAnalysisContext.Options, SupportedDiagnostics, defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.ContextSensitive, cancellationToken: operationAnalysisContext.CancellationToken), interproceduralAnalysisPredicateOpt: null); if (pointsToAnalysisResult == null) { return; } } if (sourceInfoSymbolMap.RequiresValueContentAnalysis) { valueContentAnalysisResult = ValueContentAnalysis.TryGetOrComputeResult( cfg, owningSymbol, operationAnalysisContext.Options, WellKnownTypeProvider.GetOrCreate(operationAnalysisContext.Compilation), InterproceduralAnalysisConfiguration.Create( operationAnalysisContext.Options, SupportedDiagnostics, defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.ContextSensitive, cancellationToken: operationAnalysisContext.CancellationToken), out var copyAnalysisResult, out pointsToAnalysisResult); if (valueContentAnalysisResult == null) { return; } } try { if (sourceInfoSymbolMap.IsSourceMethod( invocationOperation.TargetMethod, invocationOperation.Arguments, invocationOperation.Arguments.Select(o => pointsToAnalysisResult[o.Kind, o.Syntax]).ToImmutableArray(), invocationOperation.Arguments.Select(o => valueContentAnalysisResult[o.Kind, o.Syntax]).ToImmutableArray(), out _)) { lock (rootOperationsNeedingAnalysis) { rootOperationsNeedingAnalysis.Add(rootOperation); } } } finally { evaluateWithPointsToAnalysis?.Free(); evaluateWithValueContentAnalysis?.Free(); } }, OperationKind.Invocation); if (taintedDataConfig.HasTaintArraySource(SinkKind)) { operationBlockStartContext.RegisterOperationAction( operationAnalysisContext => { IArrayInitializerOperation arrayInitializerOperation = (IArrayInitializerOperation)operationAnalysisContext.Operation; if (arrayInitializerOperation.GetAncestor <IArrayCreationOperation>(OperationKind.ArrayCreation)?.Type is IArrayTypeSymbol arrayTypeSymbol && sourceInfoSymbolMap.IsSourceConstantArrayOfType(arrayTypeSymbol)) { lock (rootOperationsNeedingAnalysis) { rootOperationsNeedingAnalysis.Add(operationAnalysisContext.Operation.GetRoot()); } } }, OperationKind.ArrayInitializer); } operationBlockStartContext.RegisterOperationBlockEndAction( operationBlockAnalysisContext => { try { lock (rootOperationsNeedingAnalysis) { if (!rootOperationsNeedingAnalysis.Any()) { return; } foreach (IOperation rootOperation in rootOperationsNeedingAnalysis) { if (!rootOperation.TryGetEnclosingControlFlowGraph(out var cfg)) { continue; } TaintedDataAnalysisResult taintedDataAnalysisResult = TaintedDataAnalysis.TryGetOrComputeResult( cfg, operationBlockAnalysisContext.Compilation, operationBlockAnalysisContext.OwningSymbol, operationBlockAnalysisContext.Options, TaintedDataEnteringSinkDescriptor, sourceInfoSymbolMap, taintedDataConfig.GetSanitizerSymbolMap(this.SinkKind), sinkInfoSymbolMap, operationBlockAnalysisContext.CancellationToken); if (taintedDataAnalysisResult == null) { return; } foreach (TaintedDataSourceSink sourceSink in taintedDataAnalysisResult.TaintedDataSourceSinks) { if (!sourceSink.SinkKinds.Contains(this.SinkKind)) { continue; } foreach (SymbolAccess sourceOrigin in sourceSink.SourceOrigins) { // Something like: // CA3001: Potential SQL injection vulnerability was found where '{0}' in method '{1}' may be tainted by user-controlled data from '{2}' in method '{3}'. Diagnostic diagnostic = Diagnostic.Create( this.TaintedDataEnteringSinkDescriptor, sourceSink.Sink.Location, additionalLocations: new Location[] { sourceOrigin.Location }, messageArgs: new object[] { sourceSink.Sink.Symbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat), sourceSink.Sink.AccessingMethod.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat), sourceOrigin.Symbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat), sourceOrigin.AccessingMethod.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat) }); operationBlockAnalysisContext.ReportDiagnostic(diagnostic); } } } } } finally { rootOperationsNeedingAnalysis.Free(); } }); }); }); }
public override void Initialize(AnalysisContext context) { 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); }); }
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); } }); }
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);
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 <method to be analyzed, specified methods calling it></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); } } }); }