Skip to content

Commit 825f7c3

Browse files
rojiajcvickers
andauthored
CVE-2023-24936: Check type is allowed when deserializing instance types that implements INullable (#87702)
Co-authored-by: Arthur Vickers <[email protected]>
1 parent 815953a commit 825f7c3

File tree

2 files changed

+70
-0
lines changed

2 files changed

+70
-0
lines changed

src/libraries/System.Data.Common/src/System/Data/Common/SqlUDTStorage.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,9 @@ public override object ConvertXmlToObject(XmlReader xmlReader, XmlRootAttribute?
182182
}
183183
}
184184
Type type = (typeName == null) ? _dataType : Type.GetType(typeName)!;
185+
186+
TypeLimiter.EnsureTypeIsAllowed(type);
187+
185188
object Obj = System.Activator.CreateInstance(type, true)!;
186189
Debug.Assert(xmlReader is DataTextReader, "Invalid DataTextReader is being passed to customer");
187190
((IXmlSerializable)Obj).ReadXml(xmlReader);

src/libraries/System.Data.Common/tests/System/Data/RestrictedTypeHandlingTests.cs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,59 @@ public void DataTable_HonorsGloballyDefinedAllowList()
242242
}
243243
}
244244

245+
[Fact]
246+
public void DataTable_HonorsGloballyDefinedAllowListForSqlTypes()
247+
{
248+
// Arrange
249+
250+
DataTable table = new DataTable("MyTable");
251+
table.Columns.Add("MyNullableColumn", typeof(MyCustomNullable1));
252+
table.Rows.Add(new MyCustomNullable1());
253+
table.AcceptChanges();
254+
255+
var asXml = @$"<NewDataSet>
256+
<xs:schema id=""NewDataSet"" xmlns="""" xmlns:xs=""http://www.w3.org/2001/XMLSchema"" xmlns:msdata=""urn:schemas-microsoft-com:xml-msdata"">
257+
<xs:element name=""NewDataSet"" msdata:IsDataSet=""true"" msdata:MainDataTable=""MyTable"" msdata:UseCurrentLocale=""true"">
258+
<xs:complexType>
259+
<xs:choice minOccurs=""0"" maxOccurs=""unbounded"">
260+
<xs:element name=""MyTable"">
261+
<xs:complexType>
262+
<xs:sequence>
263+
<xs:element name=""MyNullableColumn"" msdata:DataType=""{typeof(MyCustomNullable1).AssemblyQualifiedName}"" type=""xs:anyType"" minOccurs=""0"" />
264+
</xs:sequence>
265+
</xs:complexType>
266+
</xs:element>
267+
</xs:choice>
268+
</xs:complexType>
269+
</xs:element>
270+
</xs:schema>
271+
<MyTable>
272+
<MyNullableColumn xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:msdata=""urn:schemas-microsoft-com:xml-msdata"" msdata:InstanceType=""{typeof(MyCustomNullable2).AssemblyQualifiedName}"">
273+
<IsNull>false</IsNull>
274+
</MyNullableColumn>
275+
</MyTable>
276+
</NewDataSet>";
277+
278+
// Act & assert
279+
// Deserialization should fail since MyCustomNullable2 is not on the allow list,
280+
// even though MyCustomNullable1 is on the allow list.
281+
282+
try
283+
{
284+
AppDomain.CurrentDomain.SetData(AppDomainDataSetDefaultAllowedTypesKey, new Type[]
285+
{
286+
typeof(MyCustomNullable1)
287+
});
288+
289+
table = new DataTable();
290+
Assert.Throws<InvalidOperationException>(() => table.ReadXml(new StringReader(asXml)));
291+
}
292+
finally
293+
{
294+
AppDomain.CurrentDomain.SetData(AppDomainDataSetDefaultAllowedTypesKey, null);
295+
}
296+
}
297+
245298
[Fact]
246299
public void DataColumn_ConvertExpression_SubjectToAllowList_Success()
247300
{
@@ -401,6 +454,20 @@ private sealed class MyCustomClass
401454
{
402455
}
403456

457+
public sealed class MyCustomNullable1 : INullable
458+
{
459+
public static MyCustomNullable1 Null { get; } = new MyCustomNullable1();
460+
461+
public bool IsNull => false;
462+
}
463+
464+
public sealed class MyCustomNullable2 : INullable
465+
{
466+
public static MyCustomNullable2 Null { get; } = new MyCustomNullable2();
467+
468+
public bool IsNull => false;
469+
}
470+
404471
public sealed class MyXmlSerializableClass : IXmlSerializable
405472
{
406473
public XmlSchema GetSchema()

0 commit comments

Comments
 (0)