-
-
Notifications
You must be signed in to change notification settings - Fork 53
/
BannedTypes.cs
196 lines (157 loc) · 5.64 KB
/
BannedTypes.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
// ReSharper disable ArgumentsStyleOther
// ReSharper disable ArgumentsStyleNamedExpression
namespace Ceras.Formatters
{
using Ceras.Helpers;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
// Some types are banned from serialization
// and instead of throwing crazy errors that don't help the user at all, we give an explanation
//
// There is only once place where we can be 100% sure that every type will eventually pass through: the type meta data entries
// so that's where we're calling it from
static class BannedTypes
{
struct BannedType
{
public readonly Type Type;
public readonly string FullName;
public readonly string BanReason;
public readonly bool AlsoCheckInherit;
public readonly Func<Type, bool> CustomIsBannedCheck;
public BannedType(Type type, string banReason, bool alsoCheckInherit)
{
Type = type;
FullName = null;
CustomIsBannedCheck = null;
BanReason = banReason;
AlsoCheckInherit = alsoCheckInherit;
}
public BannedType(string fullName, string banReason, bool alsoCheckInherit)
{
Type = null;
FullName = fullName;
CustomIsBannedCheck = null;
BanReason = banReason;
AlsoCheckInherit = alsoCheckInherit;
}
public BannedType(Func<Type, bool> customCheck, string banReason)
{
Type = null;
FullName = null;
CustomIsBannedCheck = customCheck;
BanReason = banReason;
AlsoCheckInherit = false;
}
}
static List<BannedType> _bannedTypes = new List<BannedType>();
static BannedTypes()
{
BanBase(typeof(System.Collections.IEnumerator), "Enumerators are potentially infinite, and also most likely have no way to be instantiated at deserialization-time. If you think this is a mistake, report it as a github issue or provide a custom IFormatter for this case.");
string reasonExploit = "This type can be exploited when deserializing malicious data";
Ban(typeof(System.IO.FileSystemInfo), reasonExploit);
Ban(typeof(System.Data.DataSet), reasonExploit);
Ban("System.Management.IWbemClassObjectFreeThreaded", reasonExploit);
#if NETFRAMEWORK
BanBase(typeof(System.Security.Claims.ClaimsIdentity), reasonExploit);
Ban(typeof(System.Security.Principal.WindowsIdentity), reasonExploit);
Ban(typeof(System.CodeDom.Compiler.TempFileCollection), reasonExploit);
Ban(typeof(System.Security.Policy.HashMembershipCondition), reasonExploit);
#endif
// Ban all 'native' unity objects by banning the base type.
// Component, MonoBehaviour, GameObject, Transform, ...
// If there are requests, we can add specialized formatters for them.
// Note: The types handled in the UnityAddon are structs and don't inherit from UnityEngine.Object
BanCustom(IsUnityNativeType,
reason: "Native Unity objects cannot be serialized because they're not real C#/.NET objects. It is possible to create specialized formatters for some situations so Ceras can handle those objects, but it's not really possible to do this in a general and reliable way.");
}
static bool IsUnityNativeType(Type t)
{
const string unityObject = "UnityEngine.Object";
while (t != null)
{
if(t.FullName == unityObject)
return true;
t = t.BaseType;
}
return false;
}
static void Ban(Type type, string reason) => _bannedTypes.Add(new BannedType(type, reason, false));
static void Ban(string fullName, string reason) => _bannedTypes.Add(new BannedType(fullName, reason, false));
static void BanBase(Type type, string reason) => _bannedTypes.Add(new BannedType(type, reason, true));
static void BanBase(string fullName, string reason) => _bannedTypes.Add(new BannedType(fullName, reason, true));
static void BanCustom(Func<Type, bool> isBanned, string reason) => _bannedTypes.Add(new BannedType(isBanned, reason));
internal static void ThrowIfBanned(Type type)
{
for (var i = 0; i < _bannedTypes.Count; i++)
{
var ban = _bannedTypes[i];
bool isBanned = false;
if (ban.Type != null)
{
if (ban.AlsoCheckInherit)
{
if (ban.Type.IsAssignableFrom(type))
isBanned = true;
}
else
{
if (type == ban.Type)
isBanned = true;
}
}
else if (ban.FullName != null)
{
if (ban.AlsoCheckInherit)
{
var t = type;
while (t != null)
{
if (t.FullName == ban.FullName)
{
isBanned = true;
break;
}
if (t.GetInterfaces().Any(x => x.FullName == ban.FullName))
{
isBanned = true;
break;
}
t = t.BaseType;
}
}
else
{
if (type.FullName == ban.FullName)
isBanned = true;
}
}
else if(ban.CustomIsBannedCheck != null)
{
if (ban.CustomIsBannedCheck(type))
isBanned = true;
}
else
{
Debug.Assert(false, "unreachable");
}
if (isBanned)
throw new BannedTypeException($"The type '{type.FullName}' cannot be serialized, please mark the field/property that caused this Type to be included with the [Exclude] attribute or filter it out using the 'ShouldSerialize' callback. Specific reason for this type being banned: \"{ban.BanReason}\". You should open an issue on GitHub or join the Discord server for support.");
}
}
internal static void ThrowIfNonspecific(Type type)
{
if (type.IsAbstract() || type.IsInterface || type.ContainsGenericParameters)
throw new InvalidOperationException("Can only generate code for specific types. The type " + type.FriendlyName(true) + " is abstract, or an interface, or an open generic.");
}
}
class BannedTypeException : Exception
{
public BannedTypeException(string message) : base(message)
{
}
}
}