private void AnalyzeMethodOverloads(OperationAnalysisContext context, IMethodSymbol method, ImmutableArray <IArgumentOperation> arguments, SyntaxNode expressionSyntax) { if (method.MatchMethodDerivedByName(_xmlTypes.XmlDocument, SecurityMemberNames.Load) || //FxCop CA3056 method.MatchMethodDerivedByName(_xmlTypes.XmlDocument, SecurityMemberNames.LoadXml) || //FxCop CA3057 method.MatchMethodDerivedByName(_xmlTypes.XPathDocument, WellKnownMemberNames.InstanceConstructorName) || //FxCop CA3059 method.MatchMethodDerivedByName(_xmlTypes.XmlSchema, SecurityMemberNames.Read) || //FxCop CA3060 method.MatchMethodDerivedByName(_xmlTypes.DataSet, SecurityMemberNames.ReadXml) || //FxCop CA3063 method.MatchMethodDerivedByName(_xmlTypes.DataSet, SecurityMemberNames.ReadXmlSchema) || //FxCop CA3064 method.MatchMethodDerivedByName(_xmlTypes.XmlSerializer, SecurityMemberNames.Deserialize) || //FxCop CA3070 method.MatchMethodDerivedByName(_xmlTypes.DataTable, SecurityMemberNames.ReadXml) || //FxCop CA3071 method.MatchMethodDerivedByName(_xmlTypes.DataTable, SecurityMemberNames.ReadXmlSchema)) //FxCop CA3072 { if (SecurityDiagnosticHelpers.HasXmlReaderParameter(method, _xmlTypes) < 0) { context.ReportDiagnostic(expressionSyntax.CreateDiagnostic(RuleDoNotUseDtdProcessingOverloads, method.Name)); } } else if (method.MatchMethodDerivedByName(_xmlTypes.XmlReader, SecurityMemberNames.Create)) { int xmlReaderSettingsIndex = SecurityDiagnosticHelpers.GetXmlReaderSettingsParameterIndex(method, _xmlTypes); if (xmlReaderSettingsIndex < 0) { if (method.Parameters.Length == 1 && method.Parameters[0].RefKind == RefKind.None && method.Parameters[0].Type.SpecialType == SpecialType.System_String) { // inputUri can load be a URL. Should further investigate if this is worth flagging. context.ReportDiagnostic(expressionSyntax.CreateDiagnostic(RuleXmlReaderCreateWrongOverload)); } // If no XmlReaderSettings are passed, then the default // XmlReaderSettings are used, with DtdProcessing set to Prohibit. } else if (arguments.Length > xmlReaderSettingsIndex) { IArgumentOperation arg = arguments[xmlReaderSettingsIndex]; ISymbol settingsSymbol = arg.GetReferencedMemberOrLocalOrParameter(); if (settingsSymbol == null) { return; } // If we have no XmlReaderSettingsEnvironment, then we don't know. if (_xmlReaderSettingsEnvironments.TryGetValue(settingsSymbol, out XmlReaderSettingsEnvironment env) && !env.IsDtdProcessingDisabled && !(env.IsSecureResolver && env.IsMaxCharactersFromEntitiesLimited)) { var diag = env.IsConstructedInCodeBlock ? expressionSyntax.CreateDiagnostic(RuleXmlReaderCreateInsecureConstructed) : expressionSyntax.CreateDiagnostic(RuleXmlReaderCreateInsecureInput); context.ReportDiagnostic(diag); } } } }
protected static void AnalyzeArrayLength(int length, SyntaxNode arrayCreationExpression, Action <Diagnostic> addDiagnostic) { if (length == 0) { addDiagnostic(arrayCreationExpression.CreateDiagnostic(UseEmptyEnumerableRule)); } else if (length == 1) { addDiagnostic(arrayCreationExpression.CreateDiagnostic(UseSingletonEnumerableRule)); } }
private static bool ReportDiagnosticIfNecessary(OperationAnalysisContext operationContext, IOperation argumentValue, SyntaxNode syntax, ISymbol invokedSymbol, ISymbol containingMethod) { if (argumentValue.Type.SpecialType != SpecialType.System_String || !argumentValue.ConstantValue.HasValue) { // We have a candidate for diagnostic. perform more precise dataflow analysis. var topmostBlock = argumentValue.GetTopmostParentBlock(); if (topmostBlock != null) { var cfg = ControlFlowGraph.Create(topmostBlock); var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(operationContext.Compilation); var copyAnalysisResult = CopyAnalysis.GetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider); var nullAnalysisResult = NullAnalysis.GetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider); var pointsToAnalysisResult = PointsToAnalysis.GetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider, nullAnalysisResult); var stringContentResult = StringContentAnalysis.GetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider, copyAnalysisResult, nullAnalysisResult, pointsToAnalysisResult); StringContentAbstractValue value = stringContentResult[argumentValue]; if (value.NonLiteralState == StringContainsNonLiteralState.No) { // The value is a constant literal or default/unitialized, so avoid flagging this usage. return(false); } } // Review if the symbol passed to {invocation} in {method/field/constructor/etc} has user input. operationContext.ReportDiagnostic(syntax.CreateDiagnostic(Rule, invokedSymbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat), containingMethod.Name)); return(true); } return(false); }
private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbol obsoleteAttributeType) { // FxCop compat: only analyze externally visible symbols by default if (!context.Symbol.MatchesConfiguredVisibility(context.Options, Rule, context.CancellationToken)) { return; } ImmutableArray <AttributeData> attributes = context.Symbol.GetAttributes(); foreach (AttributeData attribute in attributes) { if (attribute.AttributeClass.Equals(obsoleteAttributeType)) { // ObsoleteAttribute has a constructor that takes no params and two // other constructors that take a message as the first param. // If there are no arguments specificed or if the message argument is empty // then report a diagnostic. if (attribute.ConstructorArguments.IsEmpty || string.IsNullOrEmpty(attribute.ConstructorArguments.First().Value as string)) { SyntaxNode node = attribute.ApplicationSyntaxReference.GetSyntax(); context.ReportDiagnostic(node.CreateDiagnostic(Rule, context.Symbol.Name)); } } } }
private static bool ReportDiagnosticIfNecessary(OperationAnalysisContext operationContext, IOperation argumentValue, SyntaxNode syntax, ISymbol invokedSymbol, ISymbol containingMethod) { if (argumentValue.Type.SpecialType != SpecialType.System_String || !argumentValue.ConstantValue.HasValue) { // We have a candidate for diagnostic. perform more precise dataflow analysis. var cfg = argumentValue.GetEnclosingControlFlowGraph(); var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(operationContext.Compilation); var valueContentResult = ValueContentAnalysis.GetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider, operationContext.Options, Rule, operationContext.CancellationToken); ValueContentAbstractValue value = valueContentResult[argumentValue.Kind, argumentValue.Syntax]; if (value.NonLiteralState == ValueContainsNonLiteralState.No) { // The value is a constant literal or default/unitialized, so avoid flagging this usage. return(false); } // Review if the symbol passed to {invocation} in {method/field/constructor/etc} has user input. operationContext.ReportDiagnostic(syntax.CreateDiagnostic(Rule, invokedSymbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat), containingMethod.Name)); return(true); } return(false); }
protected void GetDiagnosticsForNode(SyntaxNode node, SemanticModel model, Action<Diagnostic> addDiagnostic) { var type = model.GetTypeInfo(node).Type; if (type != null && TypeHasWeakIdentity(type, model)) { addDiagnostic(node.CreateDiagnostic(Rule, type.ToDisplayString())); } }
protected void GetDiagnosticsForNode(SyntaxNode node, SemanticModel model, Action <Diagnostic> addDiagnostic) { var type = model.GetTypeInfo(node).Type; if (type != null && TypeHasWeakIdentity(type, model)) { addDiagnostic(node.CreateDiagnostic(Rule, type.ToDisplayString())); } }
public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.RegisterCompilationStartAction(compilationContext => { compilationContext.RegisterOperationBlockAction(operationBlockContext => { // Analyze externally visible methods with reference type parameters. if (!(operationBlockContext.OwningSymbol is IMethodSymbol containingMethod) || !containingMethod.IsExternallyVisible() || !containingMethod.Parameters.Any(p => p.Type.IsReferenceType)) { return; } // Bail out early if we have no parameter references in the method body. if (!operationBlockContext.OperationBlocks.HasAnyOperationDescendant(OperationKind.ParameterReference)) { return; } // Perform analysis of all direct/indirect parameter usages in the method to get all non-validated usages that can cause a null dereference. ImmutableDictionary <IParameterSymbol, SyntaxNode> hazardousParameterUsages = null; foreach (var operationBlock in operationBlockContext.OperationBlocks) { if (operationBlock is IBlockOperation topmostBlock) { hazardousParameterUsages = ParameterValidationAnalysis.GetOrComputeHazardousParameterUsages( topmostBlock, operationBlockContext.Compilation, containingMethod, operationBlockContext.Options, Rule, operationBlockContext.CancellationToken); break; } } if (hazardousParameterUsages != null) { foreach (var kvp in hazardousParameterUsages) { IParameterSymbol parameter = kvp.Key; SyntaxNode node = kvp.Value; // In externally visible method '{0}', validate parameter '{1}' is non-null before using it. If appropriate, throw an ArgumentNullException when the argument is null or add a Code Contract precondition asserting non-null argument. var arg1 = containingMethod.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat); var arg2 = parameter.Name; var diagnostic = node.CreateDiagnostic(Rule, arg1, arg2); operationBlockContext.ReportDiagnostic(diagnostic); } } }); }); }
private static void VerifySymbol( ISymbol?symbol, SyntaxNode node, Action <Diagnostic> reportDiagnostic, ImmutableDictionary <IAssemblySymbol, ImmutableSortedSet <string> > restrictedInternalsVisibleToMap, ConcurrentDictionary <INamespaceSymbol, bool> namespaceToIsBannedMap) { if (symbol != null && IsBannedSymbol(symbol, restrictedInternalsVisibleToMap, namespaceToIsBannedMap)) { var bannedSymbolDisplayString = symbol.ToDisplayString(SymbolDisplayFormats.QualifiedTypeAndNamespaceSymbolDisplayFormat); var assemblyName = symbol.ContainingAssembly.Name; var restrictedNamespaces = string.Join(", ", restrictedInternalsVisibleToMap[symbol.ContainingAssembly]); var diagnostic = node.CreateDiagnostic(Rule, bannedSymbolDisplayString, assemblyName, restrictedNamespaces); reportDiagnostic(diagnostic); } }
private static bool ReportDiagnosticIfNecessary(OperationAnalysisContext operationContext, IOperation argumentValue, SyntaxNode syntax, ISymbol invokedSymbol, ISymbol containingMethod) { if (argumentValue.Type.SpecialType != SpecialType.System_String || !argumentValue.ConstantValue.HasValue) { // Review if the symbol passed to {invocation} in {method/field/constructor/etc} has user input. operationContext.ReportDiagnostic(syntax.CreateDiagnostic(Rule, invokedSymbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat), containingMethod.Name)); return(true); } return(false); }
private void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbol obsoleteAttributeType) { ImmutableArray <AttributeData> attributes = context.Symbol.GetAttributes(); foreach (AttributeData attribute in attributes) { if (attribute.AttributeClass.Equals(obsoleteAttributeType)) { // ObsoleteAttribute has a constructor that takes no params and two // other constructors that take a message as the first param. // If there are no arguments specificed or if the message argument is empty // then report a diagnostic. if (attribute.ConstructorArguments.IsEmpty || string.IsNullOrEmpty(attribute.ConstructorArguments.First().Value as string)) { SyntaxNode node = attribute.ApplicationSyntaxReference.GetSyntax(); context.ReportDiagnostic(node.CreateDiagnostic(Rule, context.Symbol.Name)); } } } }
private void AnalyzeObjectCreationForXmlDocument(OperationAnalysisContext context, ISymbol variable, IObjectCreationOperation objCreation) { // create new environment representation if does not already exist if (variable == null || !_xmlDocumentEnvironments.TryGetValue(variable, out var xmlDocumentEnvironment)) { xmlDocumentEnvironment = new XmlDocumentEnvironment(_isFrameworkSecure); } xmlDocumentEnvironment.XmlDocumentDefinition = objCreation.Syntax; SyntaxNode node = objCreation.Syntax; // initial XmlResolver secure value dependent on whether framework version secure // < .NET 4.5.2 insecure - XmlDocument would set XmlResolver as XmlUrlResolver // >= .NET 4.5.2 secure - XmlDocument would set XmlResolver as null bool isXmlDocumentSecureResolver = _isFrameworkSecure; if (!Equals(objCreation.Constructor.ContainingType, _xmlTypes.XmlDocument)) { isXmlDocumentSecureResolver = true; } // propertyInitlizer is not returned any more // and no way to get propertysymbol if (objCreation.Initializer != null) { foreach (IOperation init in objCreation.Initializer.Initializers) { if (init is IAssignmentOperation assign) { var propValue = assign.Value; if (assign.Target is not IPropertyReferenceOperation propertyReference) { continue; } var prop = propertyReference.Property; if (prop.MatchPropertyDerivedByName(_xmlTypes.XmlDocument, "XmlResolver")) { if (propValue is not IConversionOperation operation) { return; } // if XmlResolver declared as XmlSecureResolver by initializer if (SecurityDiagnosticHelpers.IsXmlSecureResolverType(operation.Operand.Type, _xmlTypes)) { isXmlDocumentSecureResolver = true; } // if XmlResolver declared as null by initializer else if (SecurityDiagnosticHelpers.IsExpressionEqualsNull(operation.Operand)) { isXmlDocumentSecureResolver = true; } // otherwise insecure resolver else { context.ReportDiagnostic(assign.Syntax.CreateDiagnostic(RuleXmlDocumentWithNoSecureResolver)); return; } } else { AnalyzeNeverSetProperties(context, prop, assign.Syntax.GetLocation()); } } } } xmlDocumentEnvironment.IsSecureResolver = isXmlDocumentSecureResolver; // if XmlDocument object not temporary, add environment to dictionary if (variable != null) { _xmlDocumentEnvironments[variable] = xmlDocumentEnvironment; } // else is temporary (variable null) and XmlResolver insecure, then report now else if (!xmlDocumentEnvironment.IsSecureResolver) { context.ReportDiagnostic(node.CreateDiagnostic(RuleXmlDocumentWithNoSecureResolver)); } return; }
protected Diagnostic CreateDiagnostic(SyntaxNode node) { return node.CreateDiagnostic(Rule); }
public static Diagnostic CreateDiagnostic( this SyntaxNode node, DiagnosticDescriptor rule, ImmutableDictionary <string, string?>?properties, params object[] args) => node.CreateDiagnostic(rule, additionalLocations: ImmutableArray <Location> .Empty, properties, args);
public static Diagnostic CreateDiagnostic( this SyntaxNode node, DiagnosticDescriptor rule, params object[] args) => node.CreateDiagnostic(rule, properties: null, args);
protected override Diagnostic CreateDiagnostic(IMethodSymbol containingMethod, SyntaxNode catchNode) { return(catchNode.CreateDiagnostic(Rule, containingMethod.ToDisplayString())); }
public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.RegisterCompilationStartAction(compilationContext => { compilationContext.RegisterOperationBlockAction(operationBlockContext => { // Analyze externally visible methods with reference type parameters. if (operationBlockContext.OwningSymbol is not IMethodSymbol containingMethod || !containingMethod.IsExternallyVisible() || !containingMethod.Parameters.Any(p => p.Type.IsReferenceType) || operationBlockContext.Options.IsConfiguredToSkipAnalysis(Rule, containingMethod, operationBlockContext.Compilation)) { return; } // Bail out for protected members of sealed classes if the entire overridden method chain // is defined in the same assembly. if (containingMethod.IsOverride && containingMethod.ContainingType.IsSealed) { var overriddenMethod = containingMethod.OverriddenMethod; var hasAssemblyMismatch = false; while (overriddenMethod != null) { if (!Equals(overriddenMethod.ContainingAssembly, containingMethod.ContainingAssembly)) { hasAssemblyMismatch = true; break; } overriddenMethod = overriddenMethod.OverriddenMethod; } if (!hasAssemblyMismatch) { return; } } // Bail out early if we have no parameter references in the method body. if (!operationBlockContext.OperationBlocks.HasAnyOperationDescendant(OperationKind.ParameterReference)) { return; } // Perform analysis of all direct/indirect parameter usages in the method to get all non-validated usages that can cause a null dereference. ImmutableDictionary <IParameterSymbol, SyntaxNode>?hazardousParameterUsages = null; foreach (var operationBlock in operationBlockContext.OperationBlocks) { if (operationBlock is IBlockOperation topmostBlock) { hazardousParameterUsages = ParameterValidationAnalysis.GetOrComputeHazardousParameterUsages( topmostBlock, operationBlockContext.Compilation, containingMethod, operationBlockContext.Options, Rule); break; } } if (hazardousParameterUsages != null) { foreach (var kvp in hazardousParameterUsages) { IParameterSymbol parameter = kvp.Key; SyntaxNode node = kvp.Value; // Check if user has configured to skip extension method 'this' parameter analysis. if (containingMethod.IsExtensionMethod && Equals(containingMethod.Parameters[0], parameter)) { bool excludeThisParameterOption = operationBlockContext.Options.GetBoolOptionValue( optionName: EditorConfigOptionNames.ExcludeExtensionMethodThisParameter, rule: Rule, containingMethod, operationBlockContext.Compilation, defaultValue: false); if (excludeThisParameterOption) { continue; } } // In externally visible method '{0}', validate parameter '{1}' is non-null before using it. If appropriate, throw an ArgumentNullException when the argument is null or add a Code Contract precondition asserting non-null argument. var arg1 = containingMethod.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat); var arg2 = parameter.Name; var diagnostic = node.CreateDiagnostic(Rule, arg1, arg2); operationBlockContext.ReportDiagnostic(diagnostic); } } }); }); }
private void AnalyzeInvocation(SyntaxNodeAnalysisContext context) { var invocation = (TInvocationExpressionSyntax)context.Node; SemanticModel semanticModel = context.SemanticModel; ISymbol symbol = semanticModel.GetSymbolInfo(invocation, context.CancellationToken).Symbol; if (symbol == null || symbol.Kind != SymbolKind.Method || !symbol.Name.StartsWith("Register", StringComparison.Ordinal)) { return; } var method = (IMethodSymbol)symbol; NoteRegisterActionInvocation(method, invocation, semanticModel, context.CancellationToken); bool isRegisterSymbolAction = IsRegisterAction(DiagnosticWellKnownNames.RegisterSymbolActionName, method, _analysisContext, _compilationStartAnalysisContext); bool isRegisterSyntaxNodeAction = IsRegisterAction(DiagnosticWellKnownNames.RegisterSyntaxNodeActionName, method, _analysisContext, _compilationStartAnalysisContext, _codeBlockStartAnalysisContext); bool isRegisterCodeBlockStartAction = IsRegisterAction(DiagnosticWellKnownNames.RegisterCodeBlockStartActionName, method, _analysisContext, _compilationStartAnalysisContext); bool isRegisterOperationAction = IsRegisterAction(DiagnosticWellKnownNames.RegisterOperationActionName, method, _analysisContext, _compilationStartAnalysisContext, _operationBlockStartAnalysisContext); if (isRegisterSymbolAction || isRegisterSyntaxNodeAction || isRegisterOperationAction) { if (method.Parameters.Length == 2 && method.Parameters[1].IsParams) { IEnumerable <SyntaxNode>?arguments = GetArgumentExpressions(invocation); if (arguments != null) { int argumentCount = arguments.Count(); if (argumentCount >= 1) { ITypeSymbol type = semanticModel.GetTypeInfo(arguments.First(), context.CancellationToken).ConvertedType; if (type == null || type.Name.Equals(nameof(Action), StringComparison.Ordinal)) { if (argumentCount == 1) { DiagnosticDescriptor rule; if (isRegisterSymbolAction) { rule = MissingSymbolKindArgumentRule; } else if (isRegisterOperationAction) { rule = MissingOperationKindArgumentRule; } else { rule = MissingSyntaxKindArgumentRule; } SyntaxNode invocationExpression = GetInvocationExpression(invocation); Diagnostic diagnostic = invocationExpression.CreateDiagnostic(rule); context.ReportDiagnostic(diagnostic); } else if (isRegisterSymbolAction) { foreach (SyntaxNode argument in arguments.Skip(1)) { symbol = semanticModel.GetSymbolInfo(argument, context.CancellationToken).Symbol; if (symbol != null && symbol.Kind == SymbolKind.Field && _symbolKind.Equals(symbol.ContainingType) && !s_supportedSymbolKinds.Contains(symbol.Name)) { Diagnostic diagnostic = argument.CreateDiagnostic(UnsupportedSymbolKindArgumentRule, symbol.Name); context.ReportDiagnostic(diagnostic); } } } } } } } } if (!method.TypeParameters.IsEmpty && (isRegisterSyntaxNodeAction || isRegisterCodeBlockStartAction)) { ITypeSymbol?typeArgument = null; if (method.TypeParameters.Length == 1) { if (method.TypeParameters[0].Name == DiagnosticWellKnownNames.TLanguageKindEnumName) { typeArgument = method.TypeArguments[0]; } } else { ITypeParameterSymbol typeParam = method.TypeParameters.FirstOrDefault(t => t.Name == DiagnosticWellKnownNames.TLanguageKindEnumName); if (typeParam != null) { int index = method.TypeParameters.IndexOf(typeParam); typeArgument = method.TypeArguments[index]; } } if (typeArgument != null && typeArgument.TypeKind != TypeKind.TypeParameter && typeArgument.TypeKind != TypeKind.Error && !IsSyntaxKind(typeArgument)) { Location location = typeArgument.Locations[0]; if (!location.IsInSource) { SyntaxNode invocationExpression = GetInvocationExpression(invocation); location = invocationExpression.GetLocation(); } Diagnostic diagnostic = Diagnostic.Create(InvalidSyntaxKindTypeArgumentRule, location, typeArgument.Name, DiagnosticWellKnownNames.TLanguageKindEnumName, method.Name); context.ReportDiagnostic(diagnostic); } } }
private void AnalyzeObjectCreationForXmlDocument(OperationAnalysisContext context, ISymbol variable, IObjectCreationOperation objCreation) { if (variable == null || !_xmlDocumentEnvironments.TryGetValue(variable, out var xmlDocumentEnvironment)) { xmlDocumentEnvironment = new XmlDocumentEnvironment { IsSecureResolver = false, IsXmlResolverSet = false }; } xmlDocumentEnvironment.XmlDocumentDefinition = objCreation.Syntax; SyntaxNode node = objCreation.Syntax; bool isXmlDocumentSecureResolver = false; if (!Equals(objCreation.Constructor.ContainingType, _xmlTypes.XmlDocument)) { isXmlDocumentSecureResolver = true; } // propertyInitlizer is not returned any more // and no way to get propertysymbol if (objCreation.Initializer != null) { foreach (IOperation init in objCreation.Initializer.Initializers) { if (init is IAssignmentOperation assign) { var propValue = assign.Value; if (!(assign.Target is IPropertyReferenceOperation propertyReference)) { continue; } var prop = propertyReference.Property; if (prop.MatchPropertyDerivedByName(_xmlTypes.XmlDocument, "XmlResolver")) { if (!(propValue is IConversionOperation operation)) { return; } if (SecurityDiagnosticHelpers.IsXmlSecureResolverType(operation.Operand.Type, _xmlTypes)) { isXmlDocumentSecureResolver = true; } else if (SecurityDiagnosticHelpers.IsExpressionEqualsNull(operation.Operand)) { isXmlDocumentSecureResolver = true; } else // Non secure resolvers { context.ReportDiagnostic(assign.Syntax.CreateDiagnostic(RuleXmlDocumentWithNoSecureResolver)); return; } } else { AnalyzeNeverSetProperties(context, prop, assign.Syntax.GetLocation()); } } } } xmlDocumentEnvironment.IsSecureResolver = isXmlDocumentSecureResolver; if (variable != null) { _xmlDocumentEnvironments[variable] = xmlDocumentEnvironment; } else if (!xmlDocumentEnvironment.IsSecureResolver) // Insecure temp object { context.ReportDiagnostic(node.CreateDiagnostic(RuleXmlDocumentWithNoSecureResolver)); } return; }
private void AnalyzeNodeForXslCompiledTransformLoad(SyntaxNodeAnalysisContext context) { SyntaxNode node = context.Node; SemanticModel model = context.SemanticModel; IMethodSymbol methodSymbol = _syntaxNodeHelper.GetCalleeMethodSymbol(node, model); if (SecurityDiagnosticHelpers.IsXslCompiledTransformLoad(methodSymbol, _xmlTypes)) { bool isSecureResolver; bool isSecureSettings; bool isSetInBlock; int xmlResolverIndex = SecurityDiagnosticHelpers.GetXmlResolverParameterIndex(methodSymbol, _xmlTypes); int xsltSettingsIndex = SecurityDiagnosticHelpers.GetXsltSettingsParameterIndex(methodSymbol, _xmlTypes); // Overloads with no XmlResolver and XstlSettings specified are secure since they all have folowing behavior: // 1. An XmlUrlResolver with no user credentials is used to process any xsl:import or xsl:include elements. // 2. The document() function is disabled. // 3. Embedded scripts are not supported. if (xmlResolverIndex >= 0 && xsltSettingsIndex >= 0) { IEnumerable <SyntaxNode> argumentExpressionNodes = _syntaxNodeHelper.GetInvocationArgumentExpressionNodes(node); SyntaxNode resolverNode = argumentExpressionNodes.ElementAt(xmlResolverIndex); isSecureResolver = SyntaxNodeHelper.NodeHasConstantValueNull(resolverNode, model) || SecurityDiagnosticHelpers.IsXmlSecureResolverType(model.GetTypeInfo(resolverNode).Type, _xmlTypes); SyntaxNode settingsNode = argumentExpressionNodes.ElementAt(xsltSettingsIndex); ISymbol settingsSymbol = SyntaxNodeHelper.GetSymbol(settingsNode, model); // 1. pass null or XsltSettings.Default as XsltSetting : secure if (settingsSymbol == null || SecurityDiagnosticHelpers.IsXsltSettingsDefaultProperty(settingsSymbol as IPropertySymbol, _xmlTypes)) { isSetInBlock = true; isSecureSettings = true; } // 2. XsltSettings.TrustedXslt : insecure else if (SecurityDiagnosticHelpers.IsXsltSettingsTrustedXsltProperty(settingsSymbol as IPropertySymbol, _xmlTypes)) { isSetInBlock = true; isSecureSettings = false; } // 3. check xsltSettingsEnvironments, if IsScriptDisabled && IsDocumentFunctionDisabled then secure, else insecure else if (_xsltSettingsEnvironments.TryGetValue(settingsSymbol, out XsltSettingsEnvironment env)) { isSetInBlock = false; isSecureSettings = env.IsDocumentFunctionDisabled && env.IsScriptDisabled; } //4. symbol for settings is not found => passed in without any change => assume insecure else { isSetInBlock = true; isSecureSettings = false; } if (!isSecureSettings && !isSecureResolver) { LocalizableResourceString message = SecurityDiagnosticHelpers.GetLocalizableResourceString( isSetInBlock ? nameof(MicrosoftNetFrameworkAnalyzersResources.XslCompiledTransformLoadInsecureConstructedMessage) : nameof(MicrosoftNetFrameworkAnalyzersResources.XslCompiledTransformLoadInsecureInputMessage), SecurityDiagnosticHelpers.GetNonEmptyParentName(node, model, context.CancellationToken) ); context.ReportDiagnostic( node.CreateDiagnostic(RuleDoNotUseInsecureXSLTScriptExecution, message) ); } } } }
protected static Diagnostic CreateDiagnostic(SyntaxNode node) { return(node.CreateDiagnostic(Rule)); }
public void Analyze(OperationAnalysisContext context, ISymbol owningSymbol) { if (context.Operation.IsInvalid) { // not interested in invalid expression return; } var invocation = (IInvocationExpression)context.Operation; IMethodSymbol method = invocation.TargetMethod; SyntaxNode node = _expressionGetter(context.Operation.Syntax); if (node == null) { // we don't have right expression node to check overloads return; } // REVIEW: why IOperation doesn't contain things like compilation and semantic model? // it seems wierd that I need to do this to get thsoe. SemanticModel model = _compilation.GetSemanticModel(context.Operation.Syntax.SyntaxTree); // due to limitation of using "this" in lambda in struct INamedTypeSymbol stringType = _string; IEnumerable <IParameterSymbol> stringParameters = method.Parameters.Where(p => p.Type?.Equals(stringType) == true); if (!stringParameters.Any()) { // no string parameter. not interested. return; } // now do cheap string check whether those string parameter contains uri word list we are looking for. if (!CheckStringParametersContainUriWords(stringParameters, context.CancellationToken)) { // no string parameter that contains what we are looking for. return; } // now we make sure we actually have overloads that contains uri type parameter if (!CheckOverloadsContainUriParameters(model, method, node, context.CancellationToken)) { // no overload that contains uri as parameter return; } // now we do more expensive word parsing to find exact parameter that contains url in parameter name var indicesSet = new HashSet <int>(GetParameterIndices(method, GetStringParametersThatContainsUriWords(stringParameters, context.CancellationToken), context.CancellationToken)); // now we search exact match. this is exactly same behavior as old FxCop foreach (IMethodSymbol overload in model.GetMemberGroup(node, context.CancellationToken).OfType <IMethodSymbol>()) { context.CancellationToken.ThrowIfCancellationRequested(); if (method.Equals(overload) || overload.Parameters.Length != method.Parameters.Length) { // either itself, or signature is not same continue; } if (!CheckParameterTypes(method, overload, Enumerable.Range(0, method.Parameters.Length).Where(i => !indicesSet.Contains(i)), context.CancellationToken)) { // check whether remaining parameters match existing types, otherwise, we are not interested continue; } // original FxCop implementation doesnt account for case where original method call contains // 2+ string uri parameters that has overload with matching uri parameters. original implementation works // when there is exactly 1 parameter having matching uri overload. this implementation follow that. foreach (int index in indicesSet) { // check other string uri parameters matches original type if (!CheckParameterTypes(method, overload, indicesSet.Where(i => i != index), context.CancellationToken)) { continue; } // okay all other type match. check the main one if (overload.Parameters[index].Type?.Equals(_uri) == true) { context.ReportDiagnostic(node.CreateDiagnostic(Rule, owningSymbol.ToDisplayString(s_symbolDisplayFormat), overload.ToDisplayString(s_symbolDisplayFormat), method.ToDisplayString(s_symbolDisplayFormat))); // we no longer interested in this overload. there can be only 1 match break; } } } }