Skip to content

Commit c4cfe16

Browse files
authored
Fix a race condition between certain Has properties and their collection property. (#843)
We found a rare race condition between `MethodDefinition.HasOverrides` and `MethodDefinition.Overrides`. What can happen is 1) Thread 1 get's past the null check in `MethodDefinition.HasOverrides` and then is suspended. 2) Thread 2, calls `MethodDefinition.Overrides` and executes at least as far as the `metadata.RemoveOverrideMapping (method)` call in `AssemblyReader.ReadOverrides` 3) Thread 1 resumes on `return HasImage && Module.Read (this, (method, reader) => reader.HasOverrides (method));` It now proceeds to AssemblyReader.HasOverrides. No overrides are found and false is returned due to the overrides for that method having been removed from `MetadataSystem` To recap, the two notable behaviors are triggering this are a) The following check in `MethodDefinition.HasOverrides` happens outside of the lock. ``` if (overrides != null) return overrides.Count > 0; ``` b) The call to `metadata.RemoveOverrideMapping` in `AssemblyReader.ReadOverrides` means that `AssemblyReader.ReadOverrides` and `AssemblyReader.HasOverrides` cannot be called again after the first call to `AssemblyReader.ReadOverrides` I did not attempt to reproduce this vulnerability for every pair of properties that follows this pattern. However, I think it's safe to assume any pair of properties that follows this same pattern is vulnerable. Using `ReadingMode.Deferred` also appears to be a required prerequisite to encounter this problem. We had two thoughts on how to fix this 1) Repeat the collection null check after obtaining the module lock in `Module.Read` during `MethodDefinition.HasOverrides` 2) Remove the behavior of `AssemblyReader` removing data from the `MetadataSystem`. I decided to go with Fix 2 because it was easy to find all of problematic property pairings by searching `MetadataSystem.cs` for `Remove`. I also feel that this behavior of modifying the metadata system is asking for problems and probably not worth the freed memory is provides. If you'd prefer Fix 1 instead. Or both Fix 1 & Fix 2 let me know and I can change around the PR.
1 parent 65a2912 commit c4cfe16

File tree

2 files changed

+0
-69
lines changed

2 files changed

+0
-69
lines changed

Mono.Cecil/AssemblyReader.cs

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -899,8 +899,6 @@ public Collection<TypeDefinition> ReadNestedTypes (TypeDefinition type)
899899
nested_types.Add (nested_type);
900900
}
901901

902-
metadata.RemoveNestedTypeMapping (type);
903-
904902
return nested_types;
905903
}
906904

@@ -975,7 +973,6 @@ TypeDefinition GetNestedTypeDeclaringType (TypeDefinition type)
975973
if (!metadata.TryGetReverseNestedTypeMapping (type, out declaring_rid))
976974
return null;
977975

978-
metadata.RemoveReverseNestedTypeMapping (type);
979976
return GetTypeDefinition (declaring_rid);
980977
}
981978

@@ -1242,8 +1239,6 @@ public InterfaceImplementationCollection ReadInterfaces (TypeDefinition type)
12421239
new MetadataToken(TokenType.InterfaceImpl, mapping [i].Col1)));
12431240
}
12441241

1245-
metadata.RemoveInterfaceMapping (type);
1246-
12471242
return interfaces;
12481243
}
12491244

@@ -1466,8 +1461,6 @@ public Collection<EventDefinition> ReadEvents (TypeDefinition type)
14661461

14671462
var events = new MemberDefinitionCollection<EventDefinition> (type, (int) range.Length);
14681463

1469-
metadata.RemoveEventsRange (type);
1470-
14711464
if (range.Length == 0)
14721465
return events;
14731466

@@ -1536,8 +1529,6 @@ public Collection<PropertyDefinition> ReadProperties (TypeDefinition type)
15361529
if (!metadata.TryGetPropertiesRange (type, out range))
15371530
return new MemberDefinitionCollection<PropertyDefinition> (type);
15381531

1539-
metadata.RemovePropertiesRange (type);
1540-
15411532
var properties = new MemberDefinitionCollection<PropertyDefinition> (type, (int) range.Length);
15421533

15431534
if (range.Length == 0)
@@ -1912,8 +1903,6 @@ public Collection<GenericParameter> ReadGenericParameters (IGenericParameterProv
19121903
if (!metadata.TryGetGenericParameterRanges (provider, out ranges))
19131904
return new GenericParameterCollection (provider);
19141905

1915-
metadata.RemoveGenericParameterRange (provider);
1916-
19171906
var generic_parameters = new GenericParameterCollection (provider, RangesSize (ranges));
19181907

19191908
for (int i = 0; i < ranges.Length; i++)
@@ -2029,8 +2018,6 @@ public GenericParameterConstraintCollection ReadGenericConstraints (GenericParam
20292018
new MetadataToken (TokenType.GenericParamConstraint, mapping [i].Col1)));
20302019
}
20312020

2032-
metadata.RemoveGenericConstraintMapping (generic_parameter);
2033-
20342021
return constraints;
20352022
}
20362023

@@ -2083,8 +2070,6 @@ public Collection<MethodReference> ReadOverrides (MethodDefinition method)
20832070
for (int i = 0; i < mapping.Count; i++)
20842071
overrides.Add ((MethodReference) LookupToken (mapping [i]));
20852072

2086-
metadata.RemoveOverrideMapping (method);
2087-
20882073
return overrides;
20892074
}
20902075

@@ -2521,8 +2506,6 @@ public Collection<CustomAttribute> ReadCustomAttributes (ICustomAttributeProvide
25212506
for (int i = 0; i < ranges.Length; i++)
25222507
ReadCustomAttributeRange (ranges [i], custom_attributes);
25232508

2524-
metadata.RemoveCustomAttributeRange (owner);
2525-
25262509
if (module.IsWindowsMetadata ())
25272510
foreach (var custom_attribute in custom_attributes)
25282511
WindowsRuntimeProjections.Project (owner, custom_attribute);
@@ -2676,8 +2659,6 @@ public Collection<SecurityDeclaration> ReadSecurityDeclarations (ISecurityDeclar
26762659
for (int i = 0; i < ranges.Length; i++)
26772660
ReadSecurityDeclarationRange (ranges [i], security_declarations);
26782661

2679-
metadata.RemoveSecurityDeclarationRange (owner);
2680-
26812662
return security_declarations;
26822663
}
26832664

Mono.Cecil/MetadataSystem.cs

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -243,11 +243,6 @@ public void SetNestedTypeMapping (uint type_rid, Collection<uint> mapping)
243243
NestedTypes [type_rid] = mapping;
244244
}
245245

246-
public void RemoveNestedTypeMapping (TypeDefinition type)
247-
{
248-
NestedTypes.Remove (type.token.RID);
249-
}
250-
251246
public bool TryGetReverseNestedTypeMapping (TypeDefinition type, out uint declaring)
252247
{
253248
return ReverseNestedTypes.TryGetValue (type.token.RID, out declaring);
@@ -258,11 +253,6 @@ public void SetReverseNestedTypeMapping (uint nested, uint declaring)
258253
ReverseNestedTypes [nested] = declaring;
259254
}
260255

261-
public void RemoveReverseNestedTypeMapping (TypeDefinition type)
262-
{
263-
ReverseNestedTypes.Remove (type.token.RID);
264-
}
265-
266256
public bool TryGetInterfaceMapping (TypeDefinition type, out Collection<Row<uint, MetadataToken>> mapping)
267257
{
268258
return Interfaces.TryGetValue (type.token.RID, out mapping);
@@ -273,11 +263,6 @@ public void SetInterfaceMapping (uint type_rid, Collection<Row<uint, MetadataTok
273263
Interfaces [type_rid] = mapping;
274264
}
275265

276-
public void RemoveInterfaceMapping (TypeDefinition type)
277-
{
278-
Interfaces.Remove (type.token.RID);
279-
}
280-
281266
public void AddPropertiesRange (uint type_rid, Range range)
282267
{
283268
Properties.Add (type_rid, range);
@@ -288,11 +273,6 @@ public bool TryGetPropertiesRange (TypeDefinition type, out Range range)
288273
return Properties.TryGetValue (type.token.RID, out range);
289274
}
290275

291-
public void RemovePropertiesRange (TypeDefinition type)
292-
{
293-
Properties.Remove (type.token.RID);
294-
}
295-
296276
public void AddEventsRange (uint type_rid, Range range)
297277
{
298278
Events.Add (type_rid, range);
@@ -303,41 +283,21 @@ public bool TryGetEventsRange (TypeDefinition type, out Range range)
303283
return Events.TryGetValue (type.token.RID, out range);
304284
}
305285

306-
public void RemoveEventsRange (TypeDefinition type)
307-
{
308-
Events.Remove (type.token.RID);
309-
}
310-
311286
public bool TryGetGenericParameterRanges (IGenericParameterProvider owner, out Range [] ranges)
312287
{
313288
return GenericParameters.TryGetValue (owner.MetadataToken, out ranges);
314289
}
315290

316-
public void RemoveGenericParameterRange (IGenericParameterProvider owner)
317-
{
318-
GenericParameters.Remove (owner.MetadataToken);
319-
}
320-
321291
public bool TryGetCustomAttributeRanges (ICustomAttributeProvider owner, out Range [] ranges)
322292
{
323293
return CustomAttributes.TryGetValue (owner.MetadataToken, out ranges);
324294
}
325295

326-
public void RemoveCustomAttributeRange (ICustomAttributeProvider owner)
327-
{
328-
CustomAttributes.Remove (owner.MetadataToken);
329-
}
330-
331296
public bool TryGetSecurityDeclarationRanges (ISecurityDeclarationProvider owner, out Range [] ranges)
332297
{
333298
return SecurityDeclarations.TryGetValue (owner.MetadataToken, out ranges);
334299
}
335300

336-
public void RemoveSecurityDeclarationRange (ISecurityDeclarationProvider owner)
337-
{
338-
SecurityDeclarations.Remove (owner.MetadataToken);
339-
}
340-
341301
public bool TryGetGenericConstraintMapping (GenericParameter generic_parameter, out Collection<Row<uint, MetadataToken>> mapping)
342302
{
343303
return GenericConstraints.TryGetValue (generic_parameter.token.RID, out mapping);
@@ -348,11 +308,6 @@ public void SetGenericConstraintMapping (uint gp_rid, Collection<Row<uint, Metad
348308
GenericConstraints [gp_rid] = mapping;
349309
}
350310

351-
public void RemoveGenericConstraintMapping (GenericParameter generic_parameter)
352-
{
353-
GenericConstraints.Remove (generic_parameter.token.RID);
354-
}
355-
356311
public bool TryGetOverrideMapping (MethodDefinition method, out Collection<MetadataToken> mapping)
357312
{
358313
return Overrides.TryGetValue (method.token.RID, out mapping);
@@ -363,11 +318,6 @@ public void SetOverrideMapping (uint rid, Collection<MetadataToken> mapping)
363318
Overrides [rid] = mapping;
364319
}
365320

366-
public void RemoveOverrideMapping (MethodDefinition method)
367-
{
368-
Overrides.Remove (method.token.RID);
369-
}
370-
371321
public Document GetDocument (uint rid)
372322
{
373323
if (rid < 1 || rid > Documents.Length)

0 commit comments

Comments
 (0)