Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FIX | Removing BinaryFormatter from NetFx #869

Merged
merged 14 commits into from
Feb 18, 2021
Original file line number Diff line number Diff line change
Expand Up @@ -241,29 +241,33 @@ private static void InvokeCallback(object eventContextPair)
// END EventContextPair private class.
// ----------------------------------------

JRahnama marked this conversation as resolved.
Show resolved Hide resolved
// ----------------------------------------
// Private class for restricting allowed types from deserialization.
// ----------------------------------------

private class SqlDependencyProcessDispatcherSerializationBinder : SerializationBinder
//-----------------------------------------------
// Private Class to add ObjRef as DataContract
//-----------------------------------------------
[SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.RemotingConfiguration)]
[DataContract]
private class SqlClientObjRef : IExtensibleDataObject
{
public override Type BindToType(string assemblyName, string typeName)
[DataMember]
private static ObjRef SqlObjRef;
JRahnama marked this conversation as resolved.
Show resolved Hide resolved

public SqlClientObjRef(SqlDependencyProcessDispatcher dispatcher)
{
// Deserializing an unexpected type can inject objects with malicious side effects.
// If the type is unexpected, throw an exception to stop deserialization.
if (typeName == nameof(SqlDependencyProcessDispatcher))
{
return typeof(SqlDependencyProcessDispatcher);
}
else
{
throw new ArgumentException("Unexpected type", nameof(typeName));
}
SqlObjRef = RemotingServices.Marshal(dispatcher);
}

private ExtensionDataObject _extensionData_Value;

public ExtensionDataObject ExtensionData
JRahnama marked this conversation as resolved.
Show resolved Hide resolved
{
get => _extensionData_Value;
set => _extensionData_Value = value;
}
JRahnama marked this conversation as resolved.
Show resolved Hide resolved
}
// ----------------------------------------
// END SqlDependencyProcessDispatcherSerializationBinder private class.
// ----------------------------------------
// ------------------------------------------
// End SqlClientObjRef private class.
// -------------------------------------------

// ----------------
// Instance members
Expand Down Expand Up @@ -306,10 +310,9 @@ public override Type BindToType(string assemblyName, string typeName)
private static readonly string _typeName = (typeof(SqlDependencyProcessDispatcher)).FullName;

// -----------
// BID members
// EventSource members
// -----------


private readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount);
private static int _objectTypeCount; // EventSource Counter
internal int ObjectID
Expand All @@ -336,7 +339,7 @@ public SqlDependency(SqlCommand command) : this(command, null, SQL.SqlDependency
}

/// <include file='..\..\..\..\..\..\..\doc\snippets\Microsoft.Data.SqlClient\SqlDependency.xml' path='docs/members[@name="SqlDependency"]/ctorCommandOptionsTimeout/*' />
[System.Security.Permissions.HostProtectionAttribute(ExternalThreading = true)]
[HostProtection(ExternalThreading = true)]
public SqlDependency(SqlCommand command, string options, int timeout)
{
long scopeID = SqlClientEventSource.Log.TryNotificationScopeEnterEvent("<sc.SqlDependency|DEP> {0}, options: '{1}', timeout: '{2}'", ObjectID, options, timeout);
Expand Down Expand Up @@ -597,11 +600,13 @@ private static void ObtainProcessDispatcher()
_processDispatcher = dependency.SingletonProcessDispatcher; // Set to static instance.

// Serialize and set in native.
ObjRef objRef = GetObjRef(_processDispatcher);
BinaryFormatter formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream();
GetSerializedObject(objRef, formatter, stream);
SNINativeMethodWrapper.SetData(stream.GetBuffer()); // Native will be forced to synchronize and not overwrite.
using (MemoryStream stream = new MemoryStream())
{
SqlClientObjRef objRef = new SqlClientObjRef(_processDispatcher);
DataContractSerializer formatter = new DataContractSerializer(objRef.GetType());
JRahnama marked this conversation as resolved.
Show resolved Hide resolved
GetSerializedObject(objRef, formatter, stream);
SNINativeMethodWrapper.SetData(stream.GetBuffer()); // Native will be forced to synchronize and not overwrite.
}
}
else
{
Expand All @@ -628,35 +633,29 @@ private static void ObtainProcessDispatcher()
#if DEBUG // Possibly expensive, limit to debug.
SqlClientEventSource.Log.TryNotificationTraceEvent("<sc.SqlDependency.ObtainProcessDispatcher|DEP> AppDomain.CurrentDomain.FriendlyName: {0}", AppDomain.CurrentDomain.FriendlyName);
#endif
BinaryFormatter formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream(nativeStorage);
_processDispatcher = GetDeserializedObject(formatter, stream); // Deserialize and set for appdomain.
SqlClientEventSource.Log.TryNotificationTraceEvent("<sc.SqlDependency.ObtainProcessDispatcher|DEP> processDispatcher obtained, ID: {0}", _processDispatcher.ObjectID);
using (MemoryStream stream = new MemoryStream(nativeStorage))
{
DataContractSerializer formatter = new DataContractSerializer(typeof(SqlDependencyProcessDispatcher));
_processDispatcher = GetDeserializedObject(formatter, stream); // Deserialize and set for appdomain.
SqlClientEventSource.Log.TryNotificationTraceEvent("<sc.SqlDependency.ObtainProcessDispatcher|DEP> processDispatcher obtained, ID: {0}", _processDispatcher.ObjectID);
}
}
}

// ---------------------------------------------------------
// Static security asserted methods - limit scope of assert.
// ---------------------------------------------------------

[SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.RemotingConfiguration)]
private static ObjRef GetObjRef(SqlDependencyProcessDispatcher _processDispatcher)
{
return RemotingServices.Marshal(_processDispatcher);
}

[SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.SerializationFormatter)]
private static void GetSerializedObject(ObjRef objRef, BinaryFormatter formatter, MemoryStream stream)
private static void GetSerializedObject(SqlClientObjRef objRef, DataContractSerializer formatter, MemoryStream stream)
{
formatter.Serialize(stream, objRef);
formatter.WriteObject(stream, objRef);
}

[SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.SerializationFormatter)]
private static SqlDependencyProcessDispatcher GetDeserializedObject(BinaryFormatter formatter, MemoryStream stream)
private static SqlDependencyProcessDispatcher GetDeserializedObject(DataContractSerializer formatter, MemoryStream stream)
{
// Use a custom SerializationBinder to restrict deserialized types to SqlDependencyProcessDispatcher.
formatter.Binder = new SqlDependencyProcessDispatcherSerializationBinder();
object result = formatter.Deserialize(stream);
object result = formatter.ReadObject(stream);
Debug.Assert(result.GetType() == typeof(SqlDependencyProcessDispatcher), "Unexpected type stored in native!");
JRahnama marked this conversation as resolved.
Show resolved Hide resolved
return (SqlDependencyProcessDispatcher)result;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

using System;
using System.IO;
using System.Runtime.Serialization;
JRahnama marked this conversation as resolved.
Show resolved Hide resolved
using System.Runtime.Serialization.Formatters.Binary;
using Newtonsoft.Json;
using Xunit;
Expand Down Expand Up @@ -33,9 +34,9 @@ public void SerializationTest()
Assert.Equal(e.StackTrace, sqlEx.StackTrace);
}


[Fact]
[ActiveIssue("12161", TestPlatforms.AnyUnix)]
[ActiveIssue("12161", TargetFrameworkMonikers.Netcoreapp)]
JRahnama marked this conversation as resolved.
Show resolved Hide resolved

public static void SqlExcpetionSerializationTest()
{
var formatter = new BinaryFormatter();
Expand Down
6 changes: 3 additions & 3 deletions tools/props/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@
</PropertyGroup>
<!-- Test Project Dependencies -->
<PropertyGroup>
<MicrosoftDotNetPlatformAbstractionsVersion>3.1.1</MicrosoftDotNetPlatformAbstractionsVersion>
<MicrosoftDotNetPlatformAbstractionsVersion>3.1.6</MicrosoftDotNetPlatformAbstractionsVersion>
<MicrosoftIdentityModelClientsActiveDirectoryVersion>5.2.6</MicrosoftIdentityModelClientsActiveDirectoryVersion>
<MicrosoftNETTestSdkVersion>15.9.0</MicrosoftNETTestSdkVersion>
<MicrosoftWindowsCompatibilityVersion>3.1.0</MicrosoftWindowsCompatibilityVersion>
<MicrosoftNETTestSdkVersion>16.8.3</MicrosoftNETTestSdkVersion>
<MicrosoftWindowsCompatibilityVersion>3.1.1</MicrosoftWindowsCompatibilityVersion>
JRahnama marked this conversation as resolved.
Show resolved Hide resolved
<NewtonsoftJsonVersion>12.0.3</NewtonsoftJsonVersion>
<SystemRuntimeInteropServicesRuntimeInformationVersion>4.3.0</SystemRuntimeInteropServicesRuntimeInformationVersion>
<SystemLinqExpressionsVersion>4.3.0</SystemLinqExpressionsVersion>
Expand Down