private void AnalyzeNodeForXmlTextReaderDerivedTypeConstructorDecl(SyntaxNodeAnalysisContext context) { SyntaxNode node = context.Node; SemanticModel model = context.SemanticModel; if (!(SyntaxNodeHelper.GetDeclaredSymbol(node, model) is IMethodSymbol methodSymbol) || methodSymbol.MethodKind != MethodKind.Constructor || !((!Equals(methodSymbol.ContainingType, _xmlTypes.XmlTextReader)) && methodSymbol.ContainingType.DerivesFrom(_xmlTypes.XmlTextReader, baseTypesOnly: true))) { return; } bool hasSetSecureXmlResolver = false; bool isDtdProcessingDisabled = false; IEnumerable <SyntaxNode> assignments = _syntaxNodeHelper.GetDescendantAssignmentExpressionNodes(node); foreach (SyntaxNode assignment in assignments) { bool isTargetProperty = false; hasSetSecureXmlResolver = hasSetSecureXmlResolver || IsAssigningIntendedValueToPropertyDerivedFromType(assignment, model, (s) => { return(SecurityDiagnosticHelpers.IsXmlTextReaderXmlResolverProperty(s, _xmlTypes)); }, (n) => { return(SyntaxNodeHelper.NodeHasConstantValueNull(n, model) || SecurityDiagnosticHelpers.IsXmlSecureResolverType(model.GetTypeInfo(n).Type, _xmlTypes)); }, out isTargetProperty); if (isTargetProperty) { continue; } isDtdProcessingDisabled = isDtdProcessingDisabled || IsAssigningIntendedValueToPropertyDerivedFromType(assignment, model, (s) => { return(SecurityDiagnosticHelpers.IsXmlTextReaderDtdProcessingProperty(s, _xmlTypes)); }, (n) => { return(!SyntaxNodeHelper.GetSymbol(n, model).MatchFieldByName(_xmlTypes.DtdProcessing, SecurityMemberNames.Parse)); }, out isTargetProperty); if (hasSetSecureXmlResolver && isDtdProcessingDisabled) { return; } } DiagnosticDescriptor rule = RuleDoNotUseInsecureDtdProcessingInApiDesign; context.ReportDiagnostic( CreateDiagnostic( methodSymbol.Locations, rule, SecurityDiagnosticHelpers.GetLocalizableResourceString( nameof(MicrosoftNetFrameworkAnalyzersResources.XmlTextReaderDerivedClassConstructorNoSecureSettingsMessage), SecurityDiagnosticHelpers.GetNonEmptyParentName(node, model, context.CancellationToken) ) ) ); }
private void AnalyzeNodeForXmlTextReaderDerivedTypeMethodDecl(SyntaxNodeAnalysisContext context) { SyntaxNode node = context.Node; SemanticModel model = context.SemanticModel; IMethodSymbol methodSymbol = SyntaxNodeHelper.GetDeclaredSymbol(node, model) as IMethodSymbol; if (methodSymbol == null || !((methodSymbol.ContainingType != _xmlTypes.XmlTextReader) && methodSymbol.ContainingType.DerivesFrom(_xmlTypes.XmlTextReader, baseTypesOnly: true))) { return; } // If the default value are not secure, the AnalyzeNodeForXmlTextReaderDerivedTypeConstructorDecl would be skipped, // therefoer we need to check constructor for any insecure settings. // Otherwise, we skip checking constructors if (_isFrameworkSecure && methodSymbol.MethodKind == MethodKind.Constructor) { return; } bool hasSetXmlResolver = false; bool hasSetInsecureXmlResolver = true; bool isDtdProcessingSet = false; bool isDtdProcessingEnabled = true; List <Location> locs = null; Location insecureXmlResolverAssignLoc = null; Location issecureDtdProcessingLoc = null; IEnumerable <SyntaxNode> assignments = _syntaxNodeHelper.GetDescendantAssignmentExpressionNodes(node); foreach (SyntaxNode assignment in assignments) { bool ret; ret = IsAssigningIntendedValueToPropertyDerivedFromType(assignment, model, (s) => { return(SecurityDiagnosticHelpers.IsXmlTextReaderXmlResolverProperty(s, _xmlTypes)); }, (n) => { return(!(SyntaxNodeHelper.NodeHasConstantValueNull(n, model) || SecurityDiagnosticHelpers.IsXmlSecureResolverType(model.GetTypeInfo(n).Type, _xmlTypes))); }, out bool isTargetProperty ); if (isTargetProperty) { hasSetXmlResolver = true; hasSetInsecureXmlResolver &= ret; // use 'AND' to avoid false positives (but imcrease false negative rate) if (ret) { if (locs == null) { locs = new List <Location>(); } locs.Add(assignment.GetLocation()); } continue; } ret = IsAssigningIntendedValueToPropertyDerivedFromType(assignment, model, (s) => { return(SecurityDiagnosticHelpers.IsXmlTextReaderDtdProcessingProperty(s, _xmlTypes)); }, (n) => { return(SyntaxNodeHelper.GetSymbol(n, model).MatchFieldByName(_xmlTypes.DtdProcessing, SecurityMemberNames.Parse)); }, out isTargetProperty); if (isTargetProperty) { isDtdProcessingSet = true; isDtdProcessingEnabled &= ret; // use 'AND' to avoid false positives (but imcrease false negative rate) if (ret) { if (locs == null) { locs = new List <Location>(); } locs.Add(assignment.GetLocation()); } } } // neither XmlResolver nor DtdProcessing is explicitly set if (!(hasSetXmlResolver || isDtdProcessingSet)) { return; } // explicitly set XmlResolver and/or DtdProcessing to secure value else if (!hasSetInsecureXmlResolver || !isDtdProcessingEnabled) { return; } // didn't explicitly set either one of XmlResolver and DtdProcessing to secure value // but explicitly set XmlResolver and/or DtdProcessing to insecure value else { if (insecureXmlResolverAssignLoc != null) { locs.Add(insecureXmlResolverAssignLoc); } if (issecureDtdProcessingLoc != null) { locs.Add(issecureDtdProcessingLoc); } DiagnosticDescriptor rule = RuleDoNotUseInsecureDtdProcessingInApiDesign; // TODO: Only first location is shown in error, maybe we want to report on method instead? // Or on each insecure assignment? context.ReportDiagnostic( CreateDiagnostic( locs, rule, SecurityDiagnosticHelpers.GetLocalizableResourceString( nameof(MicrosoftNetFrameworkAnalyzersResources.XmlTextReaderDerivedClassSetInsecureSettingsInMethodMessage), methodSymbol.Name ) ) ); } }