Skip to content

Commit 5284534

Browse files
Cleanup type blacklist PR (#254)
* Move disallow unsafe type flag to settings * Code cleanup, port missing codes for netstandard 1.6 Co-authored-by: Aaron Stannard <[email protected]>
1 parent 03d7826 commit 5284534

File tree

4 files changed

+85
-49
lines changed

4 files changed

+85
-49
lines changed

src/Hyperion.API.Tests/CoreApiSpec.ApproveApi.approved.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,10 @@ namespace Hyperion
9191
public static readonly Hyperion.SerializerOptions Default;
9292
[System.Obsolete]
9393
public SerializerOptions(bool versionTolerance = false, bool preserveObjectReferences = false, System.Collections.Generic.IEnumerable<Hyperion.Surrogate> surrogates = null, System.Collections.Generic.IEnumerable<Hyperion.SerializerFactories.ValueSerializerFactory> serializerFactories = null, System.Collections.Generic.IEnumerable<System.Type> knownTypes = null, bool ignoreISerializable = false) { }
94+
[System.Obsolete]
9495
public SerializerOptions(bool versionTolerance, bool preserveObjectReferences, System.Collections.Generic.IEnumerable<Hyperion.Surrogate> surrogates, System.Collections.Generic.IEnumerable<Hyperion.SerializerFactories.ValueSerializerFactory> serializerFactories, System.Collections.Generic.IEnumerable<System.Type> knownTypes, bool ignoreISerializable, System.Collections.Generic.IEnumerable<System.Func<string, string>> packageNameOverrides) { }
96+
public SerializerOptions(bool versionTolerance, bool preserveObjectReferences, System.Collections.Generic.IEnumerable<Hyperion.Surrogate> surrogates, System.Collections.Generic.IEnumerable<Hyperion.SerializerFactories.ValueSerializerFactory> serializerFactories, System.Collections.Generic.IEnumerable<System.Type> knownTypes, bool ignoreISerializable, System.Collections.Generic.IEnumerable<System.Func<string, string>> packageNameOverrides, bool disallowUnsafeTypes) { }
97+
public Hyperion.SerializerOptions WithDisallowUnsafeType(bool disallowUnsafeType) { }
9598
public Hyperion.SerializerOptions WithIgnoreSerializable(bool ignoreISerializable) { }
9699
public Hyperion.SerializerOptions WithKnownTypes(System.Collections.Generic.IEnumerable<System.Type> knownTypes) { }
97100
public Hyperion.SerializerOptions WithPackageNameOverrides(System.Collections.Generic.IEnumerable<System.Func<string, string>> packageNameOverrides) { }

src/Hyperion/Extensions/TypeEx.cs

Lines changed: 56 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,31 @@ internal static class TypeEx
4646
public static readonly Type TypeType = typeof(Type);
4747
public static readonly Type RuntimeType = Type.GetType("System.RuntimeType");
4848

49+
private static readonly ReadOnlyCollection<string> UnsafeTypesDenySet =
50+
new ReadOnlyCollection<string>(new[]
51+
{
52+
"System.Security.Claims.ClaimsIdentity",
53+
"System.Windows.Forms.AxHost.State",
54+
"System.Windows.Data.ObjectDataProvider",
55+
"System.Management.Automation.PSObject",
56+
"System.Web.Security.RolePrincipal",
57+
"System.IdentityModel.Tokens.SessionSecurityToken",
58+
"SessionViewStateHistoryItem",
59+
"TextFormattingRunProperties",
60+
"ToolboxItemContainer",
61+
"System.Security.Principal.WindowsClaimsIdentity",
62+
"System.Security.Principal.WindowsIdentity",
63+
"System.Security.Principal.WindowsPrincipal",
64+
"System.CodeDom.Compiler.TempFileCollection",
65+
"System.IO.FileSystemInfo",
66+
"System.Activities.Presentation.WorkflowDesigner",
67+
"System.Windows.ResourceDictionary",
68+
"System.Windows.Forms.BindingSource",
69+
"Microsoft.Exchange.Management.SystemManager.WinForms.ExchangeSettingsProvider",
70+
"System.Diagnostics.Process",
71+
"System.Management.IWbemClassObjectFreeThreaded"
72+
});
73+
4974
public static bool IsHyperionPrimitive(this Type type)
5075
{
5176
return type == Int32Type ||
@@ -69,8 +94,15 @@ public static bool IsHyperionPrimitive(this Type type)
6994
}
7095

7196
#if NETSTANDARD16
72-
//HACK: the GetUnitializedObject actually exists in .NET Core, its just not public
73-
private static readonly Func<Type, object> getUninitializedObjectDelegate = (Func<Type, object>)
97+
//HACK: IsValueType does not exist for netstandard1.6
98+
private static bool IsValueType(this Type type)
99+
=> type.IsSubclassOf(typeof(ValueType));
100+
101+
private static bool IsSubclassOf(this Type p, Type c)
102+
=> c.IsAssignableFrom(p);
103+
104+
//HACK: the GetUnitializedObject actually exists in .NET Core, its just not public
105+
private static readonly Func<Type, object> GetUninitializedObjectDelegate = (Func<Type, object>)
74106
typeof(string)
75107
.GetTypeInfo()
76108
.Assembly
@@ -81,7 +113,7 @@ public static bool IsHyperionPrimitive(this Type type)
81113

82114
public static object GetEmptyObject(this Type type)
83115
{
84-
return getUninitializedObjectDelegate(type);
116+
return GetUninitializedObjectDelegate(type);
85117
}
86118
#else
87119
public static object GetEmptyObject(this Type type) => System.Runtime.Serialization.FormatterServices.GetUninitializedObject(type);
@@ -130,57 +162,39 @@ private static Type GetTypeFromManifestName(Stream stream, DeserializerSession s
130162
break;
131163
}
132164

133-
return LoadTypeByName(shortName);
165+
return LoadTypeByName(shortName, session.Serializer.Options.DisallowUnsafeTypes);
134166
});
135167
}
136168

137-
public static bool disallowUnsafeTypes = true;
138-
139-
private static ReadOnlyCollection<string> unsafeTypesDenySet =
140-
new ReadOnlyCollection<string>(new[]
141-
{
142-
"System.Security.Claims.ClaimsIdentity",
143-
"System.Windows.Forms.AxHost.State",
144-
"System.Windows.Data.ObjectDataProvider",
145-
"System.Management.Automation.PSObject",
146-
"System.Web.Security.RolePrincipal",
147-
"System.IdentityModel.Tokens.SessionSecurityToken",
148-
"SessionViewStateHistoryItem",
149-
"TextFormattingRunProperties",
150-
"ToolboxItemContainer",
151-
"System.Security.Principal.WindowsClaimsIdentity",
152-
"System.Security.Principal.WindowsIdentity",
153-
"System.Security.Principal.WindowsPrincipal",
154-
"System.CodeDom.Compiler.TempFileCollection",
155-
"System.IO.FileSystemInfo",
156-
"System.Activities.Presentation.WorkflowDesigner",
157-
"System.Windows.ResourceDictionary",
158-
"System.Windows.Forms.BindingSource",
159-
"Microsoft.Exchange.Management.SystemManager.WinForms.ExchangeSettingsProvider",
160-
"System.Diagnostics.Process",
161-
"System.Management.IWbemClassObjectFreeThreaded"
162-
});
163-
164-
#if !NETSTANDARD1_6
165-
public static bool UnsafeInheritanceCheck(Type type)
169+
private static bool UnsafeInheritanceCheck(Type type)
166170
{
171+
#if NETSTANDARD1_6
172+
if (type.IsValueType())
173+
return false;
174+
var currentBase = type.DeclaringType;
175+
#else
167176
if (type.IsValueType)
168177
return false;
169178
var currentBase = type.BaseType;
179+
#endif
180+
170181
while (currentBase != null)
171182
{
172-
if (unsafeTypesDenySet.Any(r => currentBase.FullName?.Contains(r) ?? false))
183+
if (UnsafeTypesDenySet.Any(r => currentBase.FullName?.Contains(r) ?? false))
173184
return true;
185+
#if NETSTANDARD1_6
186+
currentBase = currentBase.DeclaringType;
187+
#else
174188
currentBase = currentBase.BaseType;
189+
#endif
175190
}
176191

177192
return false;
178193
}
179-
#endif
180194

181-
public static Type LoadTypeByName(string name)
195+
public static Type LoadTypeByName(string name, bool disallowUnsafeTypes)
182196
{
183-
if (disallowUnsafeTypes && unsafeTypesDenySet.Any(r => name.Contains(r)))
197+
if (disallowUnsafeTypes && UnsafeTypesDenySet.Any(name.Contains))
184198
{
185199
throw new EvilDeserializationException(
186200
"Unsafe Type Deserialization Detected!", name);
@@ -191,24 +205,18 @@ public static Type LoadTypeByName(string name)
191205
// i.e. if there are different version available in GAC and locally
192206
var typename = ToQualifiedAssemblyName(name, ignoreAssemblyVersion: false);
193207
var type = Type.GetType(typename, true);
194-
#if NETSTANDARD1_6
195-
#else
196208
if (UnsafeInheritanceCheck(type))
197209
throw new EvilDeserializationException(
198210
"Unsafe Type Deserialization Detected!", name);
199-
#endif
200211
return type;
201212
}
202213
catch (FileLoadException)
203214
{
204215
var typename = ToQualifiedAssemblyName(name, ignoreAssemblyVersion: true);
205216
var type = Type.GetType(typename, true);
206-
#if NETSTANDARD1_6
207-
#else
208217
if (UnsafeInheritanceCheck(type))
209218
throw new EvilDeserializationException(
210219
"Unsafe Type Deserialization Detected!", name);
211-
#endif
212220
return type;
213221
}
214222
}
@@ -398,6 +406,11 @@ public class T
398406
/// </summary>
399407
private static bool IsSimilarType(this Type thisType, Type type)
400408
{
409+
if (thisType == null && type == null)
410+
return true;
411+
if (thisType == null || type == null)
412+
return false;
413+
401414
// Ignore any 'ref' types
402415
if (thisType.IsByRef)
403416
thisType = thisType.GetElementType();

src/Hyperion/SerializerOptions.cs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ public class SerializerOptions
2323
serializerFactories: null,
2424
knownTypes: null,
2525
ignoreISerializable: false,
26-
packageNameOverrides: null);
26+
packageNameOverrides: null,
27+
disallowUnsafeTypes: true);
2728

2829
internal static List<Func<string, string>> DefaultPackageNameOverrides()
2930
{
@@ -77,8 +78,8 @@ internal static List<Func<string, string>> DefaultPackageNameOverrides()
7778
internal readonly bool VersionTolerance;
7879
internal readonly Type[] KnownTypes;
7980
internal readonly Dictionary<Type, ushort> KnownTypesDict = new Dictionary<Type, ushort>();
80-
internal readonly List<Func<string, string>> CrossFrameworkPackageNameOverrides =
81-
DefaultPackageNameOverrides();
81+
internal readonly List<Func<string, string>> CrossFrameworkPackageNameOverrides = DefaultPackageNameOverrides();
82+
internal readonly bool DisallowUnsafeTypes;
8283

8384
[Obsolete]
8485
public SerializerOptions(
@@ -91,6 +92,7 @@ public SerializerOptions(
9192
: this(versionTolerance, preserveObjectReferences, surrogates, serializerFactories, knownTypes, ignoreISerializable, null)
9293
{ }
9394

95+
[Obsolete]
9496
public SerializerOptions(
9597
bool versionTolerance,
9698
bool preserveObjectReferences,
@@ -99,6 +101,18 @@ public SerializerOptions(
99101
IEnumerable<Type> knownTypes,
100102
bool ignoreISerializable,
101103
IEnumerable<Func<string, string>> packageNameOverrides)
104+
: this(versionTolerance, preserveObjectReferences, surrogates, serializerFactories, knownTypes, ignoreISerializable, null, true)
105+
{ }
106+
107+
public SerializerOptions(
108+
bool versionTolerance,
109+
bool preserveObjectReferences,
110+
IEnumerable<Surrogate> surrogates,
111+
IEnumerable<ValueSerializerFactory> serializerFactories,
112+
IEnumerable<Type> knownTypes,
113+
bool ignoreISerializable,
114+
IEnumerable<Func<string, string>> packageNameOverrides,
115+
bool disallowUnsafeTypes)
102116
{
103117
VersionTolerance = versionTolerance;
104118
Surrogates = surrogates?.ToArray() ?? EmptySurrogates;
@@ -119,6 +133,8 @@ public SerializerOptions(
119133

120134
if(packageNameOverrides != null)
121135
CrossFrameworkPackageNameOverrides.AddRange(packageNameOverrides);
136+
137+
DisallowUnsafeTypes = disallowUnsafeTypes;
122138
}
123139

124140
public SerializerOptions WithVersionTolerance(bool versionTolerance)
@@ -135,6 +151,8 @@ public SerializerOptions WithIgnoreSerializable(bool ignoreISerializable)
135151
=> Copy(ignoreISerializable: ignoreISerializable);
136152
public SerializerOptions WithPackageNameOverrides(IEnumerable<Func<string, string>> packageNameOverrides)
137153
=> Copy(packageNameOverrides: packageNameOverrides);
154+
public SerializerOptions WithDisallowUnsafeType(bool disallowUnsafeType)
155+
=> Copy(disallowUnsafeType: disallowUnsafeType);
138156

139157
private SerializerOptions Copy(
140158
bool? versionTolerance = null,
@@ -143,15 +161,17 @@ private SerializerOptions Copy(
143161
IEnumerable<ValueSerializerFactory> serializerFactories = null,
144162
IEnumerable<Type> knownTypes = null,
145163
bool? ignoreISerializable = null,
146-
IEnumerable<Func<string, string>> packageNameOverrides = null)
164+
IEnumerable<Func<string, string>> packageNameOverrides = null,
165+
bool? disallowUnsafeType = null)
147166
=> new SerializerOptions(
148167
versionTolerance ?? VersionTolerance,
149168
preserveObjectReferences ?? PreserveObjectReferences,
150169
surrogates ?? Surrogates,
151170
serializerFactories ?? ValueSerializerFactories,
152171
knownTypes ?? KnownTypes,
153172
ignoreISerializable ?? IgnoreISerializable,
154-
packageNameOverrides ?? CrossFrameworkPackageNameOverrides
173+
packageNameOverrides ?? CrossFrameworkPackageNameOverrides,
174+
disallowUnsafeType ?? DisallowUnsafeTypes
155175
);
156176
}
157177
}

src/Hyperion/ValueSerializers/TypeSerializer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public override object ReadValue(Stream stream, DeserializerSession session)
7070
return null;
7171

7272
var type = TypeNameLookup.GetOrAdd(shortname,
73-
name => TypeEx.LoadTypeByName(shortname));
73+
name => TypeEx.LoadTypeByName(shortname, session.Serializer.Options.DisallowUnsafeTypes));
7474

7575
//add the deserialized type to lookup
7676
if (session.Serializer.Options.PreserveObjectReferences)

0 commit comments

Comments
 (0)