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) }; }
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 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?generatedCodeAttributeTypeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName( WellKnownTypeNames.SystemCodeDomCompilerGeneratedCodeAttribute); // For completeness, could also consider CollectionDataContractAttribute INamedTypeSymbol?dataContractAttributeTypeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName( WellKnownTypeNames.SystemRuntimeSerializationDataContractAttribute); INamedTypeSymbol?dataMemberAttributeTypeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName( WellKnownTypeNames.SystemRuntimeSerializationDataMemberAttribute); INamedTypeSymbol?ignoreDataMemberTypeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName( WellKnownTypeNames.SystemRuntimeSerializationIgnoreDataMemberAttribute); INamedTypeSymbol?knownTypeAttributeTypeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName( WellKnownTypeNames.SystemRuntimeSerializationKnownTypeAttribute); XmlSerializationAttributeTypes xmlSerializationAttributeTypes = new XmlSerializationAttributeTypes( wellKnownTypeProvider); if (serializableAttributeTypeSymbol == null && (dataContractAttributeTypeSymbol == null || dataMemberAttributeTypeSymbol == null) && ignoreDataMemberTypeSymbol == null && knownTypeAttributeTypeSymbol == null && !xmlSerializationAttributeTypes.Any) { return; } INamedTypeSymbol?designerCategoryAttributeTypeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName( WellKnownTypeNames.SystemComponentModelDesignerCategoryAttribute); INamedTypeSymbol?typedTableBaseTypeSymbol = wellKnownTypeProvider.GetOrCreateTypeByMetadataName( WellKnownTypeNames.SystemDataTypedTableBase1); InsecureDeserializationTypeDecider decider = InsecureDeserializationTypeDecider.GetOrCreate(compilation); ConcurrentDictionary <INamedTypeSymbol, bool> visitedTypes = new ConcurrentDictionary <INamedTypeSymbol, bool>(); compilationStartAnalysisContext.RegisterSymbolAction( (SymbolAnalysisContext symbolAnalysisContext) => { INamedTypeSymbol namedTypeSymbol = (INamedTypeSymbol)symbolAnalysisContext.Symbol; bool hasSerializableAttribute = namedTypeSymbol.HasAttribute(serializableAttributeTypeSymbol); bool hasDataContractAttribute = namedTypeSymbol.HasAttribute(dataContractAttributeTypeSymbol); bool hasKnownTypeAttribute = namedTypeSymbol.HasAttribute(knownTypeAttributeTypeSymbol); bool hasAnyIgnoreDataMemberAttribute = namedTypeSymbol.GetMembers().Any(m => m.HasAttribute(ignoreDataMemberTypeSymbol)); bool hasAnyXmlSerializationAttributes = xmlSerializationAttributeTypes.HasAnyAttribute(namedTypeSymbol) || namedTypeSymbol.GetMembers().Any(m => xmlSerializationAttributeTypes.HasAnyAttribute(m)); if (!hasSerializableAttribute && !hasDataContractAttribute && !hasKnownTypeAttribute && !hasAnyIgnoreDataMemberAttribute && !hasAnyXmlSerializationAttributes) { // Don't have any attributes suggesting this class is serialized. return; } bool isProbablyAutogeneratedForGuiApp = namedTypeSymbol.HasAttribute(designerCategoryAttributeTypeSymbol) || (namedTypeSymbol.BaseType != null && namedTypeSymbol.BaseType.IsGenericType && namedTypeSymbol.BaseType.ConstructedFrom.Equals(typedTableBaseTypeSymbol)); ObjectGraphOptions options = new ObjectGraphOptions( recurse: false, binarySerialization: hasSerializableAttribute, dataContractSerialization: hasDataContractAttribute || hasAnyIgnoreDataMemberAttribute || hasKnownTypeAttribute, xmlSerialization: hasAnyXmlSerializationAttributes); if (decider.IsObjectGraphInsecure( namedTypeSymbol, options, out ImmutableArray <InsecureObjectGraphResult> results)) { DiagnosticDescriptor diagnosticToReport; if (hasSerializableAttribute) { diagnosticToReport = isProbablyAutogeneratedForGuiApp ? RceAutogeneratedSerializableContainsDangerousType : RceSerializableContainsDangerousType; } else { diagnosticToReport = SerializableContainsDangerousType; } foreach (InsecureObjectGraphResult result in results) { symbolAnalysisContext.ReportDiagnostic( Diagnostic.Create( diagnosticToReport, result.GetLocation(), result.InsecureType.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat), result.GetDisplayString())); } } }, SymbolKind.NamedType); }); }
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); }); }