From 14115ea6cdabbf9dab2c33022990131a260e170f Mon Sep 17 00:00:00 2001 From: Zsolt Kolbay <121798625+zsolt-kolbay-sonarsource@users.noreply.github.com> Date: Mon, 24 Jul 2023 15:50:42 +0200 Subject: [PATCH] S5773: VB.NET implementation (#7623) Co-authored-by: mary-georgiou-sonarsource Co-authored-by: Tim Pohlmann --- ...0E-DD76-4F4D-8250-8598140F828B}-S5773.json | 17 + analyzers/rspec/cs/S5773.json | 4 +- analyzers/rspec/vbnet/S5773.html | 106 ++++++ analyzers/rspec/vbnet/S5773.json | 33 ++ analyzers/rspec/vbnet/Sonar_way_profile.json | 1 + .../Roslyn/RestrictDeserializedTypes.cs | 39 ++- .../RestrictDeserializedTypesBase.cs | 12 +- .../SymbolicExecutionRunner.cs | 3 +- .../Roslyn/RestrictDeserializedTypes.cs | 82 +++++ .../PackagingTests/RuleTypeMappingVB.cs | 2 +- .../RestrictDeserializedTypesTest.cs | 29 ++ ...tDeserializedTypes.JavaScriptSerializer.vb | 114 ++++++ .../RestrictDeserializedTypes.LosFormatter.cs | 6 +- .../RestrictDeserializedTypes.LosFormatter.vb | 87 +++++ .../Roslyn/RestrictDeserializedTypes.vb | 325 ++++++++++++++++++ 15 files changed, 828 insertions(+), 32 deletions(-) create mode 100644 analyzers/its/expected/Ember-MM/scraper.EmberCore-{EF6A550E-DD76-4F4D-8250-8598140F828B}-S5773.json create mode 100644 analyzers/rspec/vbnet/S5773.html create mode 100644 analyzers/rspec/vbnet/S5773.json create mode 100644 analyzers/src/SonarAnalyzer.VisualBasic/SymbolicExecution/Roslyn/RestrictDeserializedTypes.cs create mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/RestrictDeserializedTypes.JavaScriptSerializer.vb create mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/RestrictDeserializedTypes.LosFormatter.vb create mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/RestrictDeserializedTypes.vb diff --git a/analyzers/its/expected/Ember-MM/scraper.EmberCore-{EF6A550E-DD76-4F4D-8250-8598140F828B}-S5773.json b/analyzers/its/expected/Ember-MM/scraper.EmberCore-{EF6A550E-DD76-4F4D-8250-8598140F828B}-S5773.json new file mode 100644 index 00000000000..a513f49762d --- /dev/null +++ b/analyzers/its/expected/Ember-MM/scraper.EmberCore-{EF6A550E-DD76-4F4D-8250-8598140F828B}-S5773.json @@ -0,0 +1,17 @@ +{ +"issues": [ +{ +"id": "S5773", +"message": "Restrict types of objects allowed to be deserialized.", +"location": { +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/Addons/scraper.EmberCore/TVScraper/clsScrapeTVDB.vb#L150", +"region": { +"startLine": 150, +"startColumn": 41, +"endLine": 150, +"endColumn": 59 +} +} +} +] +} diff --git a/analyzers/rspec/cs/S5773.json b/analyzers/rspec/cs/S5773.json index 973e3eee716..dff6cd90c4f 100644 --- a/analyzers/rspec/cs/S5773.json +++ b/analyzers/rspec/cs/S5773.json @@ -2,6 +2,7 @@ "title": "Types allowed to be deserialized should be restricted", "type": "VULNERABILITY", "status": "ready", + "quickfix": "targeted", "remediation": { "func": "Constant\/Issue", "constantCost": "30min" @@ -28,6 +29,5 @@ "5.5.1", "5.5.3" ] - }, - "quickfix": "unknown" + } } diff --git a/analyzers/rspec/vbnet/S5773.html b/analyzers/rspec/vbnet/S5773.html new file mode 100644 index 00000000000..af0ad26283d --- /dev/null +++ b/analyzers/rspec/vbnet/S5773.html @@ -0,0 +1,106 @@ +

Why is this an issue?

+

During the deserialization process, the state of an object will be reconstructed from the serialized data stream which can contain dangerous +operations.

+

For example, a well-known attack vector consists in serializing an object of type TempFileCollection +with arbitrary files (defined by an attacker) which will be deleted on the application deserializing this object (when the finalize() method of +the TempFileCollection object is called). This kind of types are called "gadgets".

+

Instead of using BinaryFormatter and similar serializers, it is recommended to use safer alternatives in most of the cases, such as XmlSerializer or DataContractSerializer. If +it’s not possible then try to mitigate the risk by restricting the types allowed to be deserialized:

+ +

Noncompliant code example

+

For BinaryFormatter, +NetDataContractSerializer, +SoapFormatter +serializers:

+
+Dim myBinaryFormatter = New BinaryFormatter()
+myBinaryFormatter.Deserialize(stream) ' Noncompliant: a binder is not used to limit types during deserialization
+
+

JavaScriptSerializer +should not use SimpleTypeResolver or other weak resolvers:

+
+Dim serializer1 As JavaScriptSerializer = New JavaScriptSerializer(New SimpleTypeResolver()) ' Noncompliant: SimpleTypeResolver is unsecure (every types is resolved)
+serializer1.Deserialize(Of ExpectedType)(json)
+
+

LosFormatter should not be used without +MAC verification:

+
+Dim formatter As LosFormatter = New LosFormatter() ' Noncompliant
+formatter.Deserialize(fs)
+
+

Compliant solution

+

BinaryFormatter, +NetDataContractSerializer +, SoapFormatter +serializers should use a binder implementing a whitelist approach to limit types during deserialization (at least one exception should be thrown or a +null value returned):

+
+NotInheritable Class CustomBinder
+    Inherits SerializationBinder
+    Public Overrides Function BindToType(assemblyName As String, typeName As String) As Type
+        If Not (Equals(typeName, "type1") OrElse Equals(typeName, "type2") OrElse Equals(typeName, "type3")) Then
+            Throw New SerializationException("Only type1, type2 and type3 are allowed") ' Compliant
+        End If
+        Return Assembly.Load(assemblyName).[GetType](typeName)
+    End Function
+End Class
+
+Dim myBinaryFormatter = New BinaryFormatter()
+myBinaryFormatter.Binder = New CustomBinder()
+myBinaryFormatter.Deserialize(stream)
+
+

JavaScriptSerializer +should use a resolver implementing a whitelist to limit types during deserialization (at least one exception should be thrown or a null value +returned):

+
+Public Class CustomSafeTypeResolver
+    Inherits JavaScriptTypeResolver
+    Public Overrides Function ResolveType(id As String) As Type
+        If Not Equals(id, "ExpectedType") Then
+            Throw New ArgumentNullException("Only ExpectedType is allowed during deserialization") ' Compliant
+        End If
+        Return Type.[GetType](id)
+    End Function
+End Class
+
+Dim serializer As JavaScriptSerializer = New JavaScriptSerializer(New CustomSafeTypeResolver()) ' Compliant
+serializer.Deserialize(Of ExpectedType)(json)
+
+

LosFormatter serializer with MAC +verification:

+
+Dim formatter As LosFormatter = New LosFormatter(True, secret) ' Compliant
+formatter.Deserialize(fs)
+
+

Resources

+ + diff --git a/analyzers/rspec/vbnet/S5773.json b/analyzers/rspec/vbnet/S5773.json new file mode 100644 index 00000000000..dff6cd90c4f --- /dev/null +++ b/analyzers/rspec/vbnet/S5773.json @@ -0,0 +1,33 @@ +{ + "title": "Types allowed to be deserialized should be restricted", + "type": "VULNERABILITY", + "status": "ready", + "quickfix": "targeted", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "30min" + }, + "tags": [ + "cwe" + ], + "defaultSeverity": "Major", + "ruleSpecification": "RSPEC-5773", + "sqKey": "S5773", + "scope": "Main", + "securityStandards": { + "CWE": [ + 502 + ], + "OWASP": [ + "A8" + ], + "OWASP Top 10 2021": [ + "A8" + ], + "ASVS 4.0": [ + "1.5.2", + "5.5.1", + "5.5.3" + ] + } +} diff --git a/analyzers/rspec/vbnet/Sonar_way_profile.json b/analyzers/rspec/vbnet/Sonar_way_profile.json index 347ba7584b1..b31d79ea262 100644 --- a/analyzers/rspec/vbnet/Sonar_way_profile.json +++ b/analyzers/rspec/vbnet/Sonar_way_profile.json @@ -133,6 +133,7 @@ "S5659", "S5693", "S5753", + "S5773", "S5856", "S5944", "S6145", diff --git a/analyzers/src/SonarAnalyzer.CSharp/SymbolicExecution/Roslyn/RestrictDeserializedTypes.cs b/analyzers/src/SonarAnalyzer.CSharp/SymbolicExecution/Roslyn/RestrictDeserializedTypes.cs index e1830a9129d..4d51aa14b30 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/SymbolicExecution/Roslyn/RestrictDeserializedTypes.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/SymbolicExecution/Roslyn/RestrictDeserializedTypes.cs @@ -35,6 +35,28 @@ public override bool ShouldExecute() return walker.Result; } + protected override SyntaxNode FindBindToTypeMethodDeclaration(IOperation operation) => + MethodCandidates(operation).FirstOrDefault(x => + x is MethodDeclarationSyntax { Identifier.Text: nameof(SerializationBinder.BindToType), ParameterList: { Parameters.Count: 2 } } method + && (method.Body is not null || method.ArrowExpressionBody() is not null) + && method.EnsureCorrectSemanticModelOrDefault(SemanticModel) is { } semanticModel + && method.ParameterList.Parameters[0].Type.IsKnownType(KnownType.System_String, semanticModel) + && method.ParameterList.Parameters[1].Type.IsKnownType(KnownType.System_String, semanticModel)); + + protected override SyntaxNode FindResolveTypeMethodDeclaration(IOperation operation) => + MethodCandidates(operation)?.FirstOrDefault(x => + x is MethodDeclarationSyntax { Identifier.Text: "ResolveType", ParameterList: { Parameters.Count: 1 } } method + && (method.Body is not null || method.ArrowExpressionBody() is not null) + && method.ParameterList.EnsureCorrectSemanticModelOrDefault(SemanticModel) is { } semanticModel + && method.ParameterList.Parameters[0].Type.IsKnownType(KnownType.System_String, semanticModel)); + + protected override bool ThrowsOrReturnsNull(SyntaxNode methodDeclaration) => ((MethodDeclarationSyntax)methodDeclaration).ThrowsOrReturnsNull(); + + protected override SyntaxToken GetIdentifier(SyntaxNode methodDeclaration) => ((MethodDeclarationSyntax)methodDeclaration).Identifier; + + private static IEnumerable MethodCandidates(IOperation operation) => + operation.Type?.DeclaringSyntaxReferences.SelectMany(x => x.GetSyntax().ChildNodes()); + private sealed class Walker : SafeCSharpSyntaxWalker { public bool Result { get; private set; } @@ -53,21 +75,4 @@ public override void VisitInvocationExpression(InvocationExpressionSyntax node) public override void VisitObjectCreationExpression(ObjectCreationExpressionSyntax node) => Result = node.Type.NameIs("LosFormatter"); } - - protected override bool IsBindToTypeMethod(SyntaxNode methodDeclaration) => - methodDeclaration is MethodDeclarationSyntax { Identifier.Text: nameof(SerializationBinder.BindToType), ParameterList.Parameters.Count: 2 } syntax - && (syntax.Body is not null || syntax.ArrowExpressionBody() is not null) - && syntax.EnsureCorrectSemanticModelOrDefault(SemanticModel) is { } semanticModel - && syntax.ParameterList.Parameters[0].Type.IsKnownType(KnownType.System_String, semanticModel) - && syntax.ParameterList.Parameters[1].Type.IsKnownType(KnownType.System_String, semanticModel); - - protected override bool IsResolveTypeMethod(SyntaxNode methodDeclaration) => - methodDeclaration is MethodDeclarationSyntax { Identifier.Text: "ResolveType", ParameterList.Parameters.Count: 1 } syntax - && (syntax.Body is not null || syntax.ArrowExpressionBody() is not null) - && syntax.EnsureCorrectSemanticModelOrDefault(SemanticModel) is { } semanticModel - && syntax.ParameterList.Parameters[0].Type.IsKnownType(KnownType.System_String, semanticModel); - - protected override bool ThrowsOrReturnsNull(SyntaxNode methodDeclaration) => ((MethodDeclarationSyntax)methodDeclaration).ThrowsOrReturnsNull(); - - protected override SyntaxToken GetIdentifier(SyntaxNode methodDeclaration) => ((MethodDeclarationSyntax)methodDeclaration).Identifier; } diff --git a/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/RuleChecks/RestrictDeserializedTypesBase.cs b/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/RuleChecks/RestrictDeserializedTypesBase.cs index 3e515a76ae2..7a3ded99805 100644 --- a/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/RuleChecks/RestrictDeserializedTypesBase.cs +++ b/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/RuleChecks/RestrictDeserializedTypesBase.cs @@ -43,8 +43,8 @@ public abstract class RestrictDeserializedTypesBase : SymbolicRuleCheck private readonly Dictionary unsafeMethodsForSymbols = new(); private readonly Dictionary unsafeMethodsForOperations = new(); - protected abstract bool IsBindToTypeMethod(SyntaxNode methodDeclaration); - protected abstract bool IsResolveTypeMethod(SyntaxNode methodDeclaration); + protected abstract SyntaxNode FindBindToTypeMethodDeclaration(IOperation operation); + protected abstract SyntaxNode FindResolveTypeMethodDeclaration(IOperation operation); protected abstract bool ThrowsOrReturnsNull(SyntaxNode methodDeclaration); protected abstract SyntaxToken GetIdentifier(SyntaxNode methodDeclaration); @@ -115,8 +115,7 @@ private bool UnsafeResolver(ProgramState state, IOperation operation, out Syntax { return true; } - else if (DeclarationCandidates(operation)?.FirstOrDefault(IsResolveTypeMethod) is { } declaration - && !ThrowsOrReturnsNull(declaration)) + else if (FindResolveTypeMethodDeclaration(operation) is { } declaration && !ThrowsOrReturnsNull(declaration)) { resolveTypeDeclaration = declaration; return true; @@ -172,14 +171,11 @@ private bool BinderIsSafe(ProgramState state, IAssignmentOperationWrapper assign } else { - bindToTypeDeclaration = DeclarationCandidates(state.ResolveCaptureAndUnwrapConversion(assignment.Value)).FirstOrDefault(IsBindToTypeMethod); + bindToTypeDeclaration = FindBindToTypeMethodDeclaration(state.ResolveCaptureAndUnwrapConversion(assignment.Value)); return bindToTypeDeclaration is null || ThrowsOrReturnsNull(bindToTypeDeclaration); } } - private static IEnumerable DeclarationCandidates(IOperation operation) => - operation.Type?.DeclaringSyntaxReferences.SelectMany(x => x.GetSyntax().ChildNodes()); - private SyntaxNode UnsafeMethodDeclaration(ProgramState state, IOperation operation) { operation = state.ResolveCaptureAndUnwrapConversion(operation); diff --git a/analyzers/src/SonarAnalyzer.VisualBasic/Rules/SymbolicExecution/SymbolicExecutionRunner.cs b/analyzers/src/SonarAnalyzer.VisualBasic/Rules/SymbolicExecution/SymbolicExecutionRunner.cs index f71d1b8f044..e15472796b0 100644 --- a/analyzers/src/SonarAnalyzer.VisualBasic/Rules/SymbolicExecution/SymbolicExecutionRunner.cs +++ b/analyzers/src/SonarAnalyzer.VisualBasic/Rules/SymbolicExecution/SymbolicExecutionRunner.cs @@ -39,7 +39,8 @@ public SymbolicExecutionRunner() : base(AnalyzerConfiguration.AlwaysEnabled) { } .Add(PublicMethodArgumentsShouldBeCheckedForNull.S3900, CreateFactory()) .Add(CalculationsShouldNotOverflow.S3949, CreateFactory()) .Add(ObjectsShouldNotBeDisposedMoreThanOnce.S3966, CreateFactory()) - .Add(EmptyCollectionsShouldNotBeEnumerated.S4158, CreateFactory()); + .Add(EmptyCollectionsShouldNotBeEnumerated.S4158, CreateFactory()) + .Add(RestrictDeserializedTypes.S5773, CreateFactory()); protected override SyntaxClassifierBase SyntaxClassifier => VisualBasicSyntaxClassifier.Instance; diff --git a/analyzers/src/SonarAnalyzer.VisualBasic/SymbolicExecution/Roslyn/RestrictDeserializedTypes.cs b/analyzers/src/SonarAnalyzer.VisualBasic/SymbolicExecution/Roslyn/RestrictDeserializedTypes.cs new file mode 100644 index 00000000000..6707cca3451 --- /dev/null +++ b/analyzers/src/SonarAnalyzer.VisualBasic/SymbolicExecution/Roslyn/RestrictDeserializedTypes.cs @@ -0,0 +1,82 @@ +/* + * SonarAnalyzer for .NET + * Copyright (C) 2015-2023 SonarSource SA + * mailto: contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +using System.Runtime.Serialization; +using StyleCop.Analyzers.Lightup; + +namespace SonarAnalyzer.SymbolicExecution.Roslyn.RuleChecks.VisualBasic; + +public sealed class RestrictDeserializedTypes : RestrictDeserializedTypesBase +{ + public static readonly DiagnosticDescriptor S5773 = DescriptorFactory.Create(DiagnosticId, MessageFormat); + + protected override DiagnosticDescriptor Rule => S5773; + + public override bool ShouldExecute() + { + var walker = new Walker(); + walker.SafeVisit(Node); + return walker.Result; + } + + protected override SyntaxNode FindBindToTypeMethodDeclaration(IOperation operation) => + MethodCandidates(operation).FirstOrDefault(x => + x is MethodBlockSyntax { SubOrFunctionStatement: { Identifier.Text: nameof(SerializationBinder.BindToType), ParameterList: { Parameters.Count: 2 } parameterList } } + && parameterList.EnsureCorrectSemanticModelOrDefault(SemanticModel) is { } semanticModel + && parameterList.Parameters[0].AsClause.Type.IsKnownType(KnownType.System_String, semanticModel) + && parameterList.Parameters[1].AsClause.Type.IsKnownType(KnownType.System_String, semanticModel)); + + protected override SyntaxNode FindResolveTypeMethodDeclaration(IOperation operation) => + MethodCandidates(operation)?.FirstOrDefault(x => + x is MethodBlockSyntax { SubOrFunctionStatement: { Identifier.Text: "ResolveType", ParameterList: { Parameters.Count: 1 } parameterList } } + && parameterList.EnsureCorrectSemanticModelOrDefault(SemanticModel) is { } semanticModel + && parameterList.Parameters[0].AsClause.Type.IsKnownType(KnownType.System_String, semanticModel)); + + protected override bool ThrowsOrReturnsNull(SyntaxNode methodDeclaration) => + methodDeclaration.DescendantNodes().OfType().Any() || + methodDeclaration.DescendantNodes().OfType().Any(expression => expression.IsKind(SyntaxKindEx.ThrowExpression)) || + methodDeclaration.DescendantNodes().OfType().Any(returnStatement => returnStatement.Expression.IsKind(SyntaxKind.NothingLiteralExpression)) || + // For simplicity this returns true for any method witch contains a NullLiteralExpression but this could be a source of FNs + methodDeclaration.DescendantNodes().OfType().Any(expression => expression.IsKind(SyntaxKind.NothingLiteralExpression)); + + protected override SyntaxToken GetIdentifier(SyntaxNode methodDeclaration) => ((MethodBlockSyntax)methodDeclaration).SubOrFunctionStatement.Identifier; + + private static IEnumerable MethodCandidates(IOperation operation) => + operation.Type?.DeclaringSyntaxReferences.SelectMany(x => x.GetSyntax().Parent.DescendantNodes()); + + private sealed class Walker : SafeVisualBasicSyntaxWalker + { + public bool Result { get; private set; } + + public override void Visit(SyntaxNode node) + { + if (!Result) + { + base.Visit(node); + } + } + + public override void VisitInvocationExpression(InvocationExpressionSyntax node) => + Result = node.NameIs(nameof(IFormatter.Deserialize)); + + public override void VisitObjectCreationExpression(ObjectCreationExpressionSyntax node) => + Result = node.Type.NameIs("LosFormatter"); + } +} diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/PackagingTests/RuleTypeMappingVB.cs b/analyzers/tests/SonarAnalyzer.UnitTest/PackagingTests/RuleTypeMappingVB.cs index fc549db1960..053882cb24d 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/PackagingTests/RuleTypeMappingVB.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/PackagingTests/RuleTypeMappingVB.cs @@ -5697,7 +5697,7 @@ internal static class RuleTypeMappingVB // ["S5770"], // ["S5771"], // ["S5772"], - // ["S5773"], + ["S5773"] = "VULNERABILITY", // ["S5774"], // ["S5775"], // ["S5776"], diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/Rules/SymbolicExecution/RestrictDeserializedTypesTest.cs b/analyzers/tests/SonarAnalyzer.UnitTest/Rules/SymbolicExecution/RestrictDeserializedTypesTest.cs index 423c3ec1456..cd58373885d 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/Rules/SymbolicExecution/RestrictDeserializedTypesTest.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/Rules/SymbolicExecution/RestrictDeserializedTypesTest.cs @@ -20,8 +20,11 @@ using SonarAnalyzer.SymbolicExecution.Sonar.Analyzers; using SonarAnalyzer.UnitTest.Helpers; + using ChecksCS = SonarAnalyzer.SymbolicExecution.Roslyn.RuleChecks.CSharp; +using ChecksVB = SonarAnalyzer.SymbolicExecution.Roslyn.RuleChecks.VisualBasic; using CS = SonarAnalyzer.Rules.CSharp; +using VB = SonarAnalyzer.Rules.VisualBasic; namespace SonarAnalyzer.UnitTest.Rules; @@ -40,6 +43,11 @@ public class RestrictDeserializedTypesTest .AddReferences(AdditionalReferences()) .WithOnlyDiagnostics(ChecksCS.RestrictDeserializedTypes.S5773); + private readonly VerifierBuilder roslynVB = new VerifierBuilder() + .WithBasePath(@"SymbolicExecution\Roslyn") + .AddReferences(AdditionalReferences()) + .WithOnlyDiagnostics(ChecksVB.RestrictDeserializedTypes.S5773); + #if NETFRAMEWORK // These serializers are available only when targeting .Net Framework [TestMethod] @@ -56,6 +64,11 @@ public void RestrictDeserializedTypesFormatters_Roslyn_CS() => roslynCS.AddPaths("RestrictDeserializedTypes.cs") .Verify(); + [TestMethod] + public void RestrictDeserializedTypesFormatters_Roslyn_VB() => + roslynVB.AddPaths("RestrictDeserializedTypes.vb") + .Verify(); + [TestMethod] public void RestrictDeserializedTypesFormatters_Roslyn_CSharp8() => roslynCS.AddPaths("RestrictDeserializedTypes.CSharp8.cs") @@ -75,6 +88,12 @@ public void RestrictDeserializedTypes_DoesNotRaiseIssuesForTestProject_Roslyn_CS .AddTestReference() .VerifyNoIssueReported(); + [TestMethod] + public void RestrictDeserializedTypes_DoesNotRaiseIssuesForTestProject_Roslyn_VB() => + roslynVB.AddPaths("RestrictDeserializedTypes.vb") + .AddTestReference() + .VerifyNoIssueReported(); + [TestMethod] public void RestrictDeserializedTypesJavaScriptSerializer_Sonar() => sonar.AddPaths("RestrictDeserializedTypes.JavaScriptSerializer.cs") @@ -86,6 +105,11 @@ public void RestrictDeserializedTypesJavaScriptSerializer_Roslyn_CS() => roslynCS.AddPaths("RestrictDeserializedTypes.JavaScriptSerializer.cs") .Verify(); + [TestMethod] + public void RestrictDeserializedTypesJavaScriptSerializer_Roslyn_VB() => + roslynVB.AddPaths("RestrictDeserializedTypes.JavaScriptSerializer.vb") + .Verify(); + [TestMethod] public void RestrictDeserializedTypesLosFormatter_Sonar() => sonar.AddPaths("RestrictDeserializedTypes.LosFormatter.cs") @@ -97,6 +121,11 @@ public void RestrictDeserializedTypesLosFormatter_Roslyn_CS() => roslynCS.AddPaths("RestrictDeserializedTypes.LosFormatter.cs") .Verify(); + [TestMethod] + public void RestrictDeserializedTypesLosFormatter_Roslyn_VB() => + roslynVB.AddPaths("RestrictDeserializedTypes.LosFormatter.vb") + .Verify(); + private static IEnumerable AdditionalReferences() => FrameworkMetadataReference.SystemRuntimeSerialization .Union(FrameworkMetadataReference.SystemRuntimeSerializationFormattersSoap) diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/RestrictDeserializedTypes.JavaScriptSerializer.vb b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/RestrictDeserializedTypes.JavaScriptSerializer.vb new file mode 100644 index 00000000000..c36d0a526b3 --- /dev/null +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/RestrictDeserializedTypes.JavaScriptSerializer.vb @@ -0,0 +1,114 @@ +Imports System +Imports System.Web.Script.Serialization + +Class Serializer + Public Sub JavaScriptSerializerDefaultConstructorIsSafe(json As String) + Call New JavaScriptSerializer().Deserialize(Of String)(json) ' Compliant - default constructor is considered safe + End Sub + + Private Shared Function CtorInitializer() As JavaScriptSerializer + Return New JavaScriptSerializer(New SimpleTypeResolver()) With { ' Compliant: deserialize method is not called + .MaxJsonLength = Integer.MaxValue + } + End Function + + Public Sub NullResolverIsSafe(json As String) + Call New JavaScriptSerializer(Nothing).Deserialize(Of String)(json) ' Compliant - a null resolver is considered safe + End Sub + + Public Sub SimpleTypeResolverIsNotSafe(json As String) + Call New JavaScriptSerializer(New SimpleTypeResolver()).Deserialize(Of String)(json) ' Noncompliant {{Restrict types of objects allowed to be deserialized.}} + End Sub + + Public Sub CustomResolver(json As String) + Call New JavaScriptSerializer(New UnsafeTypeResolver()).Deserialize(Of String)(json) ' Noncompliant [unsafeResolver1]: unsafe resolver + Call New JavaScriptSerializer(New SafeTypeResolver()).Deserialize(Of String)(json) ' Compliant: safe resolver + Call New JavaScriptSerializer(New UnsafeResolverWithOtherMethods()).Deserialize(Of String)(json) ' Noncompliant [unsafeResolver2]: unsafe resolver + Call New JavaScriptSerializer(New SafeTypeResolverWithOtherMethods()).Deserialize(Of String)(json) ' Compliant: safe resolver + End Sub + + Public Sub UnknownResolverType(json As String, resolver As JavaScriptTypeResolver) + Call New JavaScriptSerializer(resolver).Deserialize(Of String)(json) ' Compliant: the resolver type is known only at runtimme + End Sub + + Public Sub LocalVariable(json As String) + Dim unsafeResolver = New UnsafeTypeResolver() + Dim safeResolver = New SafeTypeResolver() + + Dim serializer1 = New JavaScriptSerializer(unsafeResolver) + serializer1.Deserialize(Of String)(json) ' Noncompliant [unsafeResolver3]: unsafe resolver + + Dim serializer2 = New JavaScriptSerializer(safeResolver) + serializer2.Deserialize(Of String)(json) ' Compliant: safe resolver + End Sub + + Public Function LambdaSafe(json As String) As String + Return New JavaScriptSerializer(New SafeTypeResolver()).Deserialize(Of String)(json) ' Compliant: safe resolver + End Function + + Public Function LambdaUnsafe(json As String) As String + Return New JavaScriptSerializer(New UnsafeTypeResolver()).Deserialize(Of String)(json) ' Noncompliant [unsafeResolver4] unsafe resolver + End Function +End Class + +Class UnsafeTypeResolver + Inherits JavaScriptTypeResolver + Public Overrides Function ResolveType(id As String) As Type + ' ^^^^^^^^^^^ Secondary [unsafeResolver1, unsafeResolver3, unsafeResolver4] + Return Type.GetType(id) + End Function + + Public Overrides Function ResolveTypeId(type As Type) As String + Throw New NotImplementedException() + End Function +End Class + +Class SafeTypeResolver + Inherits JavaScriptTypeResolver + Public Overrides Function ResolveType(id As String) As Type + Throw New NotImplementedException() + End Function + + Public Overrides Function ResolveTypeId(type As Type) As String + Throw New NotImplementedException() + End Function +End Class + +Class SafeTypeResolverWithOtherMethods + Inherits JavaScriptTypeResolver + Public Function BindToType(assemblyName As String, typeName As String) As Type + Return Type.GetType(typeName) + End Function + + Public Overloads Function ResolveType(id As String, wrongNumberOfParameters As String) As Type + Return Type.GetType(id) + End Function + + Public Overrides Function ResolveType(id As String) As Type + Throw New NotImplementedException() + End Function + + Public Overrides Function ResolveTypeId(type As Type) As String + Return String.Empty + End Function +End Class + +Class UnsafeResolverWithOtherMethods + Inherits JavaScriptTypeResolver + Public Function BindToType(assemblyName As String, typeName As String) As Type + Throw New NotImplementedException() + End Function + + Public Overloads Function ResolveType(id As String, wrongNumberOfParameters As String) As Type + Throw New NotImplementedException() + End Function + + Public Overrides Function ResolveType(id As String) As Type + ' ^^^^^^^^^^^ Secondary [unsafeResolver2] + Return Type.GetType(id) + End Function + + Public Overrides Function ResolveTypeId(type As Type) As String + Throw New NotImplementedException() + End Function +End Class diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/RestrictDeserializedTypes.LosFormatter.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/RestrictDeserializedTypes.LosFormatter.cs index ccff1a56e97..c37460f5911 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/RestrictDeserializedTypes.LosFormatter.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/RestrictDeserializedTypes.LosFormatter.cs @@ -64,7 +64,7 @@ public LosFormatter ExpressionBodyTrue() => public void InLambdaFunction() { Func createSafe = () => new LosFormatter(true, ""); // Compliant - MAC filtering is enabled - Func createUnsafe = () => new LosFormatter(true, ""); // Compliant - FN: lambda functions are not scanned by symbolic execution + Func createUnsafe = () => new LosFormatter(false, "");// Noncompliant } public LosFormatter Switch(bool condition) @@ -101,7 +101,7 @@ public void DataFlow() new LosFormatter(condition, ""); // Noncompliant - MAC filtering should be enabled } - new LosFormatter(new bool(), ""); // Noncompliant FP - engine does not learn bool default value - new LosFormatter(default(bool), ""); // Noncompliant FP - engine does not learn bool default value + new LosFormatter(new bool(), ""); // Noncompliant + new LosFormatter(default(bool), ""); // Noncompliant } } diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/RestrictDeserializedTypes.LosFormatter.vb b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/RestrictDeserializedTypes.LosFormatter.vb new file mode 100644 index 00000000000..1a0e000e7c1 --- /dev/null +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/RestrictDeserializedTypes.LosFormatter.vb @@ -0,0 +1,87 @@ +Imports System +Imports System.Web.UI + +Class RestrictDeserializedTypes + Public Sub DefaultConstructor() + Dim formatter = New LosFormatter() ' Noncompliant {{Serialized data signature (MAC) should be verified.}} + End Sub + + Public Sub LiteralExpression() + Dim formatter1 = New LosFormatter(False, "") ' Noncompliant + Dim formatter2 = New LosFormatter(False, New Byte(-1) {}) ' Noncompliant + Dim formatter3 = New LosFormatter(True, "") ' Compliant - MAC filtering is enabled + Dim formatter4 = New LosFormatter(True, New Byte(-1) {}) ' Compliant + Dim formatter5 = New LosFormatter(macKeyModifier:=New Byte(-1) {}, enableMac:=False) ' Noncompliant + Dim formatter6 = New LosFormatter(macKeyModifier:=New Byte(-1) {}, enableMac:=True) ' Compliant + End Sub + + Public Sub FunctionParameter(condition As Boolean) + Dim formatter1 = New LosFormatter(condition, "") ' Noncompliant + + If condition Then + Dim formatter2 = New LosFormatter(condition, "") ' Compliant + Else + Dim formatter3 = New LosFormatter(condition, "") ' Noncompliant + End If + End Sub + + Public Sub LocalVariables() + Dim trueVar = True + Dim formatter1 = New LosFormatter(trueVar, "") ' Compliant + Dim falseVar = False + Dim formatter2 = New LosFormatter(falseVar, "") ' Noncompliant + End Sub + + Public Sub TernaryOp(condition As Boolean) + Dim falseVar = If(condition, False, False) + Dim formatter1 = New LosFormatter(falseVar, "") ' Noncompliant + Dim trueVar = If(condition, True, True) + Dim formatter2 = New LosFormatter(trueVar, "") ' Compliant + Dim formatter3 = New LosFormatter(If(condition, False, True), "") ' Noncompliant + End Sub + + Public Function UnsafeReturnValue() As LosFormatter + Return New LosFormatter(False, "") ' Noncompliant + End Function + + Public Function SafeReturnValue() As LosFormatter + Return New LosFormatter(True, "") + End Function + + Public Sub InLambdaFunction() + Dim createSafe As Func(Of LosFormatter) = Function() New LosFormatter(True, "") ' Compliant + Dim createUnsafe As Func(Of LosFormatter) = Function() New LosFormatter(False, "") ' Noncompliant + End Sub + + Public Function Switch(condition As Boolean) As LosFormatter + Select Case condition + Case True + Return New LosFormatter(condition, "") ' Noncompliant - FP: engine does not learn from switch branches + Case Else + Return New LosFormatter(condition, "") ' Noncompliant + End Select + End Function + + Public Sub DataFlow() + Dim condition = False + condition = True + + If condition Then + Dim formatter1 = New LosFormatter(condition, "") + Else + Dim formatter2 = New LosFormatter(condition, "") ' Unreachable + End If + + condition = False + + If condition Then + Dim formatter3 = New LosFormatter(condition, "") ' Unreachable + Else + Dim formatter4 = New LosFormatter(condition, "") ' Noncompliant + End If + + Dim formatter5 = New LosFormatter(New Boolean(), "") ' Noncompliant + Dim formatter6 = New LosFormatter(Nothing, "") ' Noncompliant + End Sub + +End Class diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/RestrictDeserializedTypes.vb b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/RestrictDeserializedTypes.vb new file mode 100644 index 00000000000..575798d871d --- /dev/null +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/RestrictDeserializedTypes.vb @@ -0,0 +1,325 @@ +Imports System +Imports System.IO +Imports System.Reflection +Imports System.Runtime.Serialization +Imports System.Runtime.Serialization.Formatters +Imports System.Runtime.Serialization.Formatters.Binary +Imports System.Runtime.Serialization.Formatters.Soap + +Imports System.Web.UI + +Imports AliasedBinaryFormatter = System.Runtime.Serialization.Formatters.Binary.BinaryFormatter + + +Friend Class Serializer + + Friend Sub BinaryFormatterDeserialize(ByVal memoryStream As MemoryStream) + Call New BinaryFormatter().Deserialize(memoryStream) ' Noncompliant {{Restrict types of objects allowed to be deserialized.}} + ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + End Sub + + Friend Sub NetDataContractSerializerDeserialize() + Call New NetDataContractSerializer().Deserialize(New MemoryStream()) ' Noncompliant {{Restrict types of objects allowed to be deserialized.}} + End Sub + + Friend Sub SoapFormatterDeserialize() + Call New SoapFormatter().Deserialize(New MemoryStream()) ' Noncompliant {{Restrict types of objects allowed to be deserialized.}} + End Sub + + Friend Sub BinderAsVariable(ByVal stream As Stream, ByVal condition As Boolean) + Dim safeBinder = New SafeBinderStatementWithReturnNothing() + Dim unsafeBinder = New UnsafeBinder() + Dim nothingBinder As SerializationBinder = Nothing + + Dim formatter1 = New BinaryFormatter() + formatter1.Binder = safeBinder + formatter1.Deserialize(stream) ' Compliant: safe binder was used + + Dim formatter2 = New BinaryFormatter() + formatter2.Binder = unsafeBinder + formatter2.Deserialize(stream) ' Noncompliant [unsafeBinder1]: unsafe binder used + + Dim formatter3 = New BinaryFormatter() + formatter3.Binder = nothingBinder + formatter3.Deserialize(stream) ' Noncompliant: the binder is Nothing + + Dim possibleNothingBinder = If(condition, Nothing, New SafeBinderStatementWithReturnNothing()) + Dim formatter4 = New BinaryFormatter() + formatter4.Binder = possibleNothingBinder + formatter4.Deserialize(stream) ' Noncompliant: the binder is Nothing + + Dim formatter5 = New BinaryFormatter() + If condition Then + formatter5.Binder = New SafeBinderStatementWithReturnNothing() + End If + formatter5.Deserialize(stream) ' Noncompliant: the binder is Nothing + + Dim formatter6 = New BinaryFormatter() + formatter6.Binder = New SafeBinderExpressionWithNothing() + formatter6.Binder = New UnsafeBinder() + formatter6.Deserialize(stream) ' Noncompliant [unsafeBinder2]: the last binder set is unsafe + + Dim formatter7 = New BinaryFormatter With {.Binder = New SafeBinderExpressionWithNothing()} + formatter7.Binder = New UnsafeBinder() + formatter7.Deserialize(stream) ' Noncompliant [unsafeBinder3]: the last binder set is unsafe + + Dim formatter8 = New BinaryFormatter() + formatter8.Binder = New UnsafeBinder() + formatter8.Binder = New SafeBinderExpressionWithNothing() + formatter8.Deserialize(stream) ' Compliant: the last binder set is safe + + Dim formatter9 = New BinaryFormatter With {.Binder = New UnsafeBinder()} + formatter9.Binder = New SafeBinderExpressionWithNothing() + formatter9.Deserialize(stream) ' Compliant: the last binder set is safe + + Dim formatter10 = New BinaryFormatter With {.Binder = New UnsafeBinder()} + formatter10.Deserialize(stream) ' Noncompliant [unsafeBinder4]: the safe binder was set after deserialize call + formatter10.Binder = New SafeBinderExpressionWithNothing() + + Dim formatter15 = New BinaryFormatter() + Dim formatter16 = New BinaryFormatter() + Try + formatter15.Binder = New SafeBinderExpressionWithNothing() + formatter15.Deserialize(stream) ' Compliant: safe binder + + formatter16.Binder = New UnsafeBinder() + formatter16.Deserialize(stream) ' Noncompliant [unsafeBinder5]: unsafe binder + Catch + formatter15.Deserialize(stream) ' Noncompliant + formatter16.Deserialize(stream) ' Noncompliant + End Try + + While True + Dim formatter17 = New BinaryFormatter With {.Binder = New SafeBinderExpressionWithNothing()} + formatter17.Deserialize(stream) + + Dim formatter18 = New BinaryFormatter With {.Binder = New UnsafeBinder()} + formatter18.Deserialize(stream) ' Noncompliant [unsafeBinder6]: unsafe binder + End While + + End Sub + + Private Sub Functions(ByVal stream As Stream) + Dim binderFactoryUnsafe As Func(Of UnsafeBinder) = Function() New UnsafeBinder() + Call New BinaryFormatter With {.Binder = binderFactoryUnsafe()}.Deserialize(stream) ' Noncompliant [unsafeBinder7]: unsafe binder used + + Dim binderFactorySafe As Func(Of SafeBinderExpressionWithNothing) = Function() New SafeBinderExpressionWithNothing() + Call New BinaryFormatter With {.Binder = binderFactorySafe()}.Deserialize(stream) + Call New BinaryFormatter With {.Binder = binderFactoryUnsafe()}.Deserialize(stream) ' Noncompliant [unsafeBinder8]: unsafe binder used + Call New BinaryFormatter With {.Binder = binderFactorySafe()}.Deserialize(stream) + End Sub + + Private Shared Function BinderFactoryUnsafe() As UnsafeBinder + Return New UnsafeBinder() + End Function + + Private Shared Function BinderFactorySafe() As SafeBinderExpressionWithNothing + Return New SafeBinderExpressionWithNothing() + End Function + + Friend Sub DeserializeOnExpression(ByVal memoryStream As MemoryStream, ByVal condition As Boolean) + Call New BinaryFormatter().Deserialize(memoryStream) ' Noncompliant: the binder is Nothing + Call New BinaryFormatter With {.Binder = Nothing}.Deserialize(memoryStream) ' Noncompliant: the binder is Nothing + Call (If(condition, New BinaryFormatter(), Nothing)).Deserialize(memoryStream) ' FN: the binder is Nothing + Dim bin As BinaryFormatter = Nothing + Call New BinaryFormatter With {.Binder = New SafeBinderStatementWithReturnNothing()}.Deserialize(memoryStream) ' Compliant: the binder is safe + Call New BinaryFormatter With {.Binder = New UnsafeBinder()}.Deserialize(memoryStream) ' Noncompliant [unsafeBinder9]: the binder is unsafe + Call (If(condition, New BinaryFormatter With {.Binder = New SafeBinderStatementWithReturnNothing()}, New BinaryFormatter With {.Binder = New SafeBinderWithThrowStatement()})).Deserialize(memoryStream) ' Compliant: the binder is safe in all cases + End Sub + + Friend Sub Switch(ByVal stream As Stream, ByVal condition As Boolean, ByVal number As Integer) + Dim formatter4 = New BinaryFormatter() + + Select Case number + Case 1 + formatter4.Deserialize(stream) ' Noncompliant: the binder is Nothing + Case 2 + formatter4.Binder = Nothing + formatter4.Deserialize(stream) ' Noncompliant [nothingBinder1]: the binder is Nothing + Case 3 + formatter4.Binder = New UnsafeBinder() + formatter4.Deserialize(stream) ' Noncompliant [unsafeBinder10]: the binder is unsafe + Case Else + formatter4.Binder = New SafeBinderExpressionWithNothing() + formatter4.Deserialize(stream) ' Compliant: the binder is safe + End Select + End Sub + + Friend Sub BinderCases(ByVal memoryStream As MemoryStream) + Dim formatter = New BinaryFormatter() + formatter.Binder = New SafeBinderStatementWithReturnNothing() + formatter.Deserialize(memoryStream) ' Compliant: the binder is safe + formatter.Binder = New SafeBinderWithThrowStatement() + formatter.Deserialize(memoryStream) ' Compliant: the binder is safe + formatter.Binder = New SafeBinderWithThrowExpression() + formatter.Deserialize(memoryStream) ' Compliant: the binder is safe + formatter.Binder = New UnsafeBinder() + formatter.Deserialize(memoryStream) ' Noncompliant [unsafeBinder11]: the binder is unsafe + formatter.Binder = New UnsafeBinderExpressionBody() + formatter.Deserialize(memoryStream) ' Noncompliant [unsafeBinder12]: the binder is unsafe + formatter.Binder = New SafeBinderWithOtherMethods() + formatter.Deserialize(memoryStream) ' Compliant: the binder is safe + formatter.Binder = New UnsafeBinderWithOtherMethods() + formatter.Deserialize(memoryStream) ' Noncompliant [unsafeBinder13]: the binder is unsafe + End Sub + + Friend Sub UnknownBindersAreSafe(ByVal binder As SerializationBinder, ByVal condition As Boolean) + Call New BinaryFormatter With {.Binder = binder}.Deserialize(New MemoryStream()) + Dim formatter = New BinaryFormatter With {.Binder = binder} + formatter.Deserialize(New MemoryStream()) + Call New BinaryFormatter() With {.Binder = If(condition, CType(New SafeBinderExpressionWithNothing(), SerializationBinder), New UnsafeBinder())}.Deserialize(New MemoryStream()) ' Noncompliant [unsafeBinder14]: the binder is unsafe on at least one path + End Sub + + Friend Function UnknownBinaryFormattersAreSafeByDefault(ByVal formatter As BinaryFormatter) As BinaryFormatter + formatter.Deserialize(New MemoryStream()) + formatter.Binder = New UnsafeBinder() + formatter.Deserialize(New MemoryStream()) ' Noncompliant [unsafeBinder15]: the binder is unsafe + formatter = UnknownBinaryFormattersAreSafeByDefault(Nothing) + formatter.Deserialize(New MemoryStream()) + formatter.Binder = New UnsafeBinder() + formatter.Deserialize(New MemoryStream()) ' Noncompliant [unsafeBinder16]: the binder is unsafe + BinaryFormatterField.Deserialize(New MemoryStream()) + BinaryFormatterField.Binder = New UnsafeBinder() + BinaryFormatterField.Deserialize(New MemoryStream()) ' Noncompliant [unsafeBinder17]: the binder is unsafe + Return Nothing + End Function + + Friend Sub UnknownFormattersAreSafeByDefault(ByVal formatter As IFormatter) + formatter.Binder = New UnsafeBinder() + formatter.Deserialize(New MemoryStream()) + End Sub + + Private BinaryFormatterField As BinaryFormatter +End Class + + + +Namespace Aliases + Class BinaryFormatter + Private Property Binder As SerializationBinder + + Private Function Deserialize(ByVal serializationStream As Stream) As Object + Return Nothing + End Function + + Private Sub Test() + Call New AliasedBinaryFormatter().Deserialize(New MemoryStream()) ' Noncompliant: the binder is Nothing + Call New BinaryFormatter().Deserialize(New MemoryStream()) + End Sub + End Class +End Namespace + + +Friend NotInheritable Class SafeBinderStatementWithReturnNothing + Inherits SerializationBinder + + Public Overrides Function BindToType(ByVal assemblyName As String, ByVal typeName As System.String) As Type + If typeName = "typeT" Then + Return Assembly.Load(assemblyName).[GetType](typeName) + End If + + Return Nothing + End Function + +End Class + +Friend NotInheritable Class SafeBinderExpressionWithNothing + Inherits SerializationBinder + + Public Overrides Function BindToType(ByVal assemblyName As String, ByVal typeName As String) As Type + Return If(typeName = "typeT", Assembly.Load(assemblyName).[GetType](typeName), Nothing) + End Function +End Class + +Friend NotInheritable Class SafeBinderStatementWithNothing + Inherits SerializationBinder + + Public Overrides Function BindToType(ByVal assemblyName As String, ByVal typeName As String) As Type + Return If(typeName = "typeT", Assembly.Load(assemblyName).[GetType](typeName), Nothing) + End Function + +End Class + +Friend NotInheritable Class SafeBinderWithThrowStatement + Inherits SerializationBinder + + Public Overrides Function BindToType(ByVal assemblyName As String, ByVal typeName As String) As Type + If typeName = "typeT" Then + Return Assembly.Load(assemblyName).[GetType](typeName) + Else + Throw New SerializationException("An exception has occurred.") + End If + End Function + +End Class + +Friend NotInheritable Class SafeBinderWithThrowExpression + Inherits SerializationBinder + + Public Overrides Function BindToType(ByVal assemblyName As String, ByVal typeName As String) As Type + If typeName = "typeT" Then + Return Assembly.Load(assemblyName).[GetType](typeName) + Else + Throw New SerializationException("An exception has occurred.") + End If + End Function + +End Class + +Friend NotInheritable Class UnsafeBinder + Inherits SerializationBinder + + Public Overrides Function BindToType(ByVal assemblyName As String, ByVal typeName As String) As Type ' FP: nothingBinder1 + ' ^^^^^^^^^^ Secondary [unsafeBinder1, unsafeBinder2, unsafeBinder3, unsafeBinder4, unsafeBinder5, unsafeBinder6, unsafeBinder7, unsafeBinder8, unsafeBinder9, unsafeBinder10, unsafeBinder11, unsafeBinder14, unsafeBinder15, unsafeBinder16, unsafeBinder17, nothingBinder1] + Return Assembly.Load(assemblyName).[GetType](typeName) + End Function +End Class + +Friend NotInheritable Class UnsafeBinderExpressionBody + Inherits SerializationBinder + + Public Overrides Function BindToType(ByVal assemblyName As String, ByVal typeName As String) As Type + ' ^^^^^^^^^^ Secondary [unsafeBinder12] + Return Assembly.Load(assemblyName).[GetType](typeName) + End Function + +End Class + +Friend NotInheritable Class UnsafeBinderWithOtherMethods + Inherits SerializationBinder + + Public Sub Accept() + End Sub + + Public Function ResolveType(ByVal id As String) As Type + Throw New SerializationException("Not implemented.") + End Function + + Public Overloads Function BindToType(ByVal assemblyName As String) As Type + Throw New SerializationException("Not implemented.") + End Function + + Public Overloads Function BindToType(ByVal assemblyName As String, ByVal typeName As Integer) As Type + Throw New SerializationException("Not implemented.") + End Function + + Public Overrides Function BindToType(ByVal assemblyName As String, ByVal typeName As String) As Type + ' ^^^^^^^^^^ Secondary [unsafeBinder13] + Return Assembly.Load(assemblyName).[GetType](typeName) + End Function +End Class + +Friend NotInheritable Class SafeBinderWithOtherMethods + Inherits SerializationBinder + + Public Sub Accept() + End Sub + + Public Function ResolveType(ByVal id As String) As Type + Return Type.[GetType](id) + End Function + + Public Overrides Function BindToType(ByVal assemblyName As String, ByVal typeName As String) As Type + Throw New SerializationException("Only typeT is allowed") + End Function +End Class