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:
+
+ - by implementing an "allow-list" of types, but keep in mind that novel dangerous types are regularly discovered and this protection could be
+ insufficient over time.
+ - or/and implementing a tamper protection, such as message authentication codes (MAC). This way
+ only objects serialized with the correct MAC hash will 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