diff options
author | Samuel Arzt <arzt.samuel@live.de> | 2017-10-19 20:48:11 +0300 |
---|---|---|
committer | Jan Kotas <jkotas@microsoft.com> | 2017-10-19 20:48:11 +0300 |
commit | 4d4d738ab3f3c558b297d2d5481fc6e4b4f8a7f9 (patch) | |
tree | 114f9635ff65544b9948ebbe7ac8ee400349f80f /src/ILVerify | |
parent | 65209c45e21aeb73351459480ecbc7756642b73b (diff) |
[ILVerify] Implement type / method / field access verifications (#4762)
* WIP: Implemented class and method access verification.
* Changed access verifications to appropriately cast to EcmaType/Method.
* Added test cases for type / method access verifications.
* Implemented method signature access verification.
* Added test cases for method signature access verification.
* Implemented field access verification.
* Added tests for field access verification.
* Added special test case for accessing family field of superclass of containing class. Refactored some AccessTest names.
* Added additional instance parameter to field/method access checks, to check family access.
* Implemented access verification for friend assemblies.
* Added relevant PEVerify code part for security critical code.
* Added try-catch to public key comparison.
Diffstat (limited to 'src/ILVerify')
-rw-r--r-- | src/ILVerify/src/AccessVerificationHelpers.cs | 345 | ||||
-rw-r--r-- | src/ILVerify/src/ILImporter.Verify.cs | 48 | ||||
-rw-r--r-- | src/ILVerify/src/ILVerify.csproj | 1 | ||||
-rw-r--r-- | src/ILVerify/src/Resources/Strings.resx | 6 | ||||
-rw-r--r-- | src/ILVerify/src/VerifierError.cs | 4 | ||||
-rw-r--r-- | src/ILVerify/tests/ILTests/AccessTests.il | 398 | ||||
-rw-r--r-- | src/ILVerify/tests/ILTests/AccessTestsExtern.il | 152 | ||||
-rw-r--r-- | src/ILVerify/tests/ILTests/AccessTestsFriend.il | 26 | ||||
-rw-r--r-- | src/ILVerify/tests/TestDataLoader.cs | 4 |
9 files changed, 966 insertions, 18 deletions
diff --git a/src/ILVerify/src/AccessVerificationHelpers.cs b/src/ILVerify/src/AccessVerificationHelpers.cs new file mode 100644 index 000000000..c2345b137 --- /dev/null +++ b/src/ILVerify/src/AccessVerificationHelpers.cs @@ -0,0 +1,345 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Diagnostics; +using System.Reflection; +using Internal.TypeSystem; +using Internal.TypeSystem.Ecma; + +namespace ILVerify +{ + internal static class AccessVerificationHelpers + { + /// <summary> + /// Returns whether the class <paramref name="currentClass"/> can access the class <paramref name="targetClass"/>. + /// </summary> + internal static bool CanAccess(this TypeDesc currentClass, TypeDesc targetClass) + { + if (targetClass.IsGenericParameter || targetClass.IsSignatureVariable) + return true; // Generic parameters are always accessible + + if (targetClass.IsParameterizedType) + return currentClass.CanAccess(((ParameterizedType)targetClass).ParameterType); + +#if false + // perform transparency check on the type, if the caller is transparent + if ((NULL != pCurrentMD) && Security::IsTransparentMethod(pCurrentMD)) + { + // check if type is visible outside the assembly + if (!IsTypeVisibleOutsideAssembly(pTargetClass)) + { + // check transparent/critical on type + if (!Security::CheckNonPublicCriticalAccess(pCurrentMD, NULL, NULL, pTargetClass)) + return FALSE; + } + } +#endif + + // Check access to class instantiations if generic class + if (targetClass.HasInstantiation && !currentClass.CanAccessInstantiation(targetClass.Instantiation)) + return false; + + var currentTypeDef = (MetadataType)currentClass.GetTypeDefinition(); + var targetTypeDef = (EcmaType)targetClass.GetTypeDefinition(); + + var targetContainingType = targetTypeDef.ContainingType; + if (targetContainingType == null) + { + // a non-nested class can be either all public or accessible only from its own assembly (and friends) + if ((targetTypeDef.Attributes & TypeAttributes.Public) != 0) + return true; + else + return currentTypeDef.Module == targetTypeDef.Module || targetTypeDef.Module.GrantsFriendAccessTo(currentTypeDef.Module); + } + + // Target class is nested + MethodAttributes visibility = NestedToMethodAccessAttribute(targetTypeDef.Attributes); + + // Translate access check into member access check, i.e. check whether the current class can access + // a member of the enclosing class with the visibility of target class + return currentTypeDef.CanAccessMember(targetContainingType, visibility, null); + } + + /// <summary> + /// Returns whether the class '<paramref name="currentClass"/>' can access the method '<paramref name="targetMethod"/>' through + /// the instance '<paramref name="instance"/>'. The instance can be null, if the method to be accessed is static. + /// </summary> + internal static bool CanAccess(this TypeDesc currentType, MethodDesc targetMethod, TypeDesc instance = null) + { + // If generic method, check instantiation access + if (targetMethod.HasInstantiation && !currentType.CanAccessInstantiation(targetMethod.Instantiation)) + return false; + + var targetMethodDef = (EcmaMethod)targetMethod.GetTypicalMethodDefinition(); + var currentTypeDef = (MetadataType)currentType.GetTypeDefinition(); + + if (!currentTypeDef.CanAccessMember(targetMethod.OwningType, targetMethodDef.Attributes & MethodAttributes.MemberAccessMask, instance)) + return false; + + return currentTypeDef.CanAccessMethodSignature(targetMethod); + } + + /// <summary> + /// Returns whether the class '<paramref name="currentClass"/>' can access the field '<paramref name="targetField"/>' through + /// the instance '<paramref name="instance"/>'. The instance can be null, if the field to be accessed is static. + /// </summary> + internal static bool CanAccess(this TypeDesc currentType, FieldDesc targetField, TypeDesc instance = null) + { + // Check access to field owning type + var targetFieldDef = (EcmaField)targetField.GetTypicalFieldDefinition(); + var currentTypeDef = (MetadataType)currentType.GetTypeDefinition(); + + var targetFieldAccess = FieldToMethodAccessAttribute(targetFieldDef.Attributes); + + if (!currentTypeDef.CanAccessMember(targetField.OwningType, targetFieldAccess, instance)) + return false; + + // Check access to field type itself + return currentType.CanAccess(targetField.FieldType); + } + + private static bool CanAccessMember(this MetadataType currentType, TypeDesc targetType, MethodAttributes memberVisibility, TypeDesc instance) + { + if (instance == null) + instance = currentType; + + // Check access to class defining member + if (!currentType.CanAccess(targetType)) + return false; + + var targetTypeDef = (MetadataType)targetType.GetTypeDefinition(); + + if (memberVisibility == MethodAttributes.Public) + return true; + + // This is module-scope checking, to support C++ file & function statics. + if (memberVisibility == MethodAttributes.PrivateScope) + return currentType.Module == targetTypeDef.Module; + + if (memberVisibility == MethodAttributes.Assembly) + return currentType.Module == targetTypeDef.Module || targetTypeDef.Module.GrantsFriendAccessTo(currentType.Module); + + if (memberVisibility == MethodAttributes.FamANDAssem) + { + if (currentType.Module != targetTypeDef.Module && !targetTypeDef.Module.GrantsFriendAccessTo(currentType.Module)) + return false; + } + + // Nested classes can access all members of their parent class. + do + { + // Classes have access to all of their own members + if (currentType == targetTypeDef) + return true; + + switch (memberVisibility) + { + case MethodAttributes.FamORAssem: + if (currentType.Module == targetTypeDef.Module || targetTypeDef.Module.GrantsFriendAccessTo(currentType.Module)) + return true; + + // Check if current class is subclass of target + if (CanAccessFamily(currentType, targetTypeDef, instance)) + return true; + break; + case MethodAttributes.Family: + case MethodAttributes.FamANDAssem: + // Assembly acces was already checked earlier, so only need to check family access + if (CanAccessFamily(currentType, targetTypeDef, instance)) + return true; + break; + case MethodAttributes.Private: + break; // Already handled by loop + default: + Debug.Assert(false); + break; + } + + var containingType = currentType.ContainingType; + if (containingType != null) + currentType = (MetadataType)containingType.GetTypeDefinition(); + else + currentType = null; + } while (currentType != null); + + return false; + } + + private static bool CanAccessInstantiation(this TypeDesc currentType, Instantiation instantiation) + { + foreach (var inst in instantiation) + { + if (!currentType.CanAccess(inst)) + return false; + } + + return true; + } + + private static bool CanAccessMethodSignature(this TypeDesc currentType, MethodDesc targetMethod) + { + var methodSig = targetMethod.Signature; + + // Check return type + var returnType = methodSig.ReturnType; + if (returnType.IsParameterizedType) + returnType = ((ParameterizedType)returnType).ParameterType; + + if (!returnType.IsGenericParameter && !returnType.IsSignatureVariable // Generic parameters are always accessible + && !returnType.IsVoid) + { + if (!currentType.CanAccess(returnType)) + return false; + } + + // Check arguments + for (int i = 0; i < methodSig.Length; ++i) + { + var param = methodSig[i]; + if (param.IsByRef) + param = ((ByRefType)param).ParameterType; + + if (param.IsGenericParameter || param.IsSignatureVariable) + continue; // Generic parameters are always accessible + + if (!currentType.CanAccess(param)) + return false; + } + + return true; + } + + private static bool CanAccessFamily(TypeDesc currentType, TypeDesc targetTypeDef, TypeDesc instanceType) + { + // Iterate through all containing types of instance + while (instanceType != null) + { + var curInstTypeDef = instanceType; + var currentTypeDef = currentType.GetTypeDefinition(); + // Iterate through all super types of current instance type + while (curInstTypeDef != null) + { + if (currentTypeDef == curInstTypeDef.GetTypeDefinition()) + { + // At this point we know that the instance type is able to access the same family fields as current type + // Now iterate through all super types of current type to see if current type can access family target type + while (currentTypeDef != null) + { + if (currentTypeDef == targetTypeDef) + return true; + + currentTypeDef = currentTypeDef.BaseType; + if (currentTypeDef != null) + currentTypeDef = currentTypeDef.GetTypeDefinition(); + } + + return false; + } + + curInstTypeDef = curInstTypeDef.BaseType; + } + + instanceType = ((MetadataType)instanceType.GetTypeDefinition()).ContainingType; + } + + return false; + } + + private const string PUBLIC_KEY = "PublicKey="; + + private static bool GrantsFriendAccessTo(this ModuleDesc module, ModuleDesc friendModule) + { + var assembly = (EcmaAssembly)module; + var friendAssembly = (IAssemblyDesc)friendModule; + + var friendName = friendAssembly.GetName(); + var friendPublicKey = friendName.GetPublicKey(); + + foreach (var attribute in assembly.GetDecodedCustomAttributes("System.Runtime.CompilerServices", "InternalsVisibleToAttribute")) + { + var friendValues = ((string)attribute.FixedArguments[0].Value).Split(", "); + if (friendValues.Length >= 1 && friendValues.Length <= 2) + { + if (friendValues[0] != friendName.Name) + continue; + + if (friendValues.Length == 2 && + (!friendValues[1].StartsWith(PUBLIC_KEY) || !IsSamePublicKey(friendPublicKey, friendValues[1].Substring(PUBLIC_KEY.Length)))) + continue; + + return true; + } + } + return false; + } + + private static bool IsSamePublicKey(byte[] key1, string key2) + { + if (key1.Length * 2 != key2.Length) + return false; + + for (int i = 0; i < key1.Length; i++) + { + try + { + if (key1[i] != Convert.ToByte(key2[i * 2] + "" + key2[i * 2 + 1], 16)) + return false; + } + catch + { + return false; + } + } + + return true; + } + + private static MethodAttributes NestedToMethodAccessAttribute(TypeAttributes nestedVisibility) + { + switch (nestedVisibility & TypeAttributes.VisibilityMask) + { + case TypeAttributes.NestedAssembly: + return MethodAttributes.Assembly; + case TypeAttributes.NestedFamANDAssem: + return MethodAttributes.FamANDAssem; + case TypeAttributes.NestedFamily: + return MethodAttributes.Family; + case TypeAttributes.NestedFamORAssem: + return MethodAttributes.FamORAssem; + case TypeAttributes.NestedPrivate: + return MethodAttributes.Private; + case TypeAttributes.NestedPublic: + return MethodAttributes.Public; + default: + Debug.Assert(false); + return MethodAttributes.Public; + } + } + + private static MethodAttributes FieldToMethodAccessAttribute(FieldAttributes attributes) + { + switch (attributes & FieldAttributes.FieldAccessMask) + { + case FieldAttributes.Assembly: + return MethodAttributes.Assembly; + case FieldAttributes.FamANDAssem: + return MethodAttributes.FamANDAssem; + case FieldAttributes.Family: + return MethodAttributes.Family; + case FieldAttributes.FamORAssem: + return MethodAttributes.FamORAssem; + case FieldAttributes.Private: + return MethodAttributes.Private; + case FieldAttributes.PrivateScope: + return MethodAttributes.PrivateScope; + case FieldAttributes.Public: + return MethodAttributes.Public; + default: + Debug.Assert(false); + return MethodAttributes.Public; + } + } + } +} diff --git a/src/ILVerify/src/ILImporter.Verify.cs b/src/ILVerify/src/ILImporter.Verify.cs index 980f718c7..41ce6434a 100644 --- a/src/ILVerify/src/ILImporter.Verify.cs +++ b/src/ILVerify/src/ILImporter.Verify.cs @@ -1207,6 +1207,8 @@ again: } } + TypeDesc instance = null; + if (opcode == ILOpcode.newobj) { // TODO: @@ -1215,6 +1217,7 @@ again: if (methodType != null) { var actualThis = Pop(allowUninitThis: true); + instance = actualThis.Type; var declaredThis = methodType.IsValueType ? StackValue.CreateByRef(methodType) : StackValue.CreateObjRef(methodType); @@ -1294,16 +1297,8 @@ again: VerificationError(VerifierError.UnsatisfiedMethodParentInst, method.OwningType); else if (!method.CheckConstraints(_instantiationContext)) VerificationError(VerifierError.UnsatisfiedMethodInst, method); -#if false - // Access verifications - handleMemberAccessForVerification(callInfo.accessAllowed, callInfo.callsiteCalloutHelper, - MVER_E_METHOD_ACCESS); - if (mflags & CORINFO_FLG_PROTECTED) - { - Verify(m_jitInfo->canAccessFamily(getCurrentMethodHandle(), instanceClassHnd), MVER_E_METHOD_ACCESS); - } -#endif + Check(_method.OwningType.CanAccess(method, instance), VerifierError.MethodAccess); TypeDesc returnType = sig.ReturnType; @@ -1375,9 +1370,13 @@ again: NO_WAY("Currently do not support LDFTN of Parameterized functions"); #endif + TypeDesc instance; + if (opCode == ILOpcode.ldftn) { _delegateCreateStart = _currentInstructionOffset; + + instance = null; } else if (opCode == ILOpcode.ldvirtftn) { @@ -1393,6 +1392,7 @@ again: declaredType = StackValue.CreateFromType(method.OwningType); var thisPtr = Pop(); + instance = thisPtr.Type; CheckIsObjRef(thisPtr); CheckIsAssignable(thisPtr, declaredType); @@ -1409,13 +1409,7 @@ again: else if (!method.CheckConstraints(_instantiationContext)) VerificationError(VerifierError.UnsatisfiedMethodInst, method); -#if false - Verify(m_jitInfo->canAccessMethod(getCurrentMethodHandle(), //from - methodClassHnd, // in - methHnd, // what - instanceClassHnd), - MVER_E_METHOD_ACCESS); -#endif + Check(_method.OwningType.CanAccess(method, instance), VerifierError.MethodAccess); Push(StackValue.CreateMethod(method)); } @@ -1683,9 +1677,13 @@ again: var field = ResolveFieldToken(token); + TypeDesc instance; + if (isStatic) { Check(field.IsStatic, VerifierError.ExpectedStaticField); + + instance = null; } else { @@ -1702,8 +1700,12 @@ again: StackValue.CreateByRef(owningType) : StackValue.CreateObjRef(owningType); CheckIsAssignable(actualThis, declaredThis); + + instance = actualThis.Type; } + Check(_method.OwningType.CanAccess(field, instance), VerifierError.FieldAccess); + Push(StackValue.CreateFromType(field.FieldType)); } @@ -1712,11 +1714,14 @@ again: var field = ResolveFieldToken(token); bool isPermanentHome = false; + TypeDesc instance; + if (isStatic) { Check(field.IsStatic, VerifierError.ExpectedStaticField); isPermanentHome = true; + instance = null; } else { @@ -1735,8 +1740,11 @@ again: CheckIsAssignable(actualThis, declaredThis); isPermanentHome = actualThis.Kind == StackValueKind.ObjRef || actualThis.IsPermanentHome; + instance = actualThis.Type; } + Check(_method.OwningType.CanAccess(field, instance), VerifierError.FieldAccess); + Push(StackValue.CreateByRef(field.FieldType, false, isPermanentHome)); } @@ -1749,9 +1757,13 @@ again: var field = ResolveFieldToken(token); + TypeDesc instance; + if (isStatic) { Check(field.IsStatic, VerifierError.ExpectedStaticField); + + instance = null; } else { @@ -1768,8 +1780,12 @@ again: StackValue.CreateByRef(owningType) : StackValue.CreateObjRef(owningType); CheckIsAssignable(actualThis, declaredThis); + + instance = actualThis.Type; } + Check(_method.OwningType.CanAccess(field, instance), VerifierError.FieldAccess); + CheckIsAssignable(value, StackValue.CreateFromType(field.FieldType)); } diff --git a/src/ILVerify/src/ILVerify.csproj b/src/ILVerify/src/ILVerify.csproj index 0a7950bab..615183886 100644 --- a/src/ILVerify/src/ILVerify.csproj +++ b/src/ILVerify/src/ILVerify.csproj @@ -17,6 +17,7 @@ <Compile Include="SimpleTypeSystemContext.cs" /> <Compile Include="VerifierError.cs" /> <Compile Include="TypeSystemHelpers.cs" /> + <Compile Include="AccessVerificationHelpers.cs" /> </ItemGroup> <ItemGroup> diff --git a/src/ILVerify/src/Resources/Strings.resx b/src/ILVerify/src/Resources/Strings.resx index 868a917fb..543e9b44f 100644 --- a/src/ILVerify/src/Resources/Strings.resx +++ b/src/ILVerify/src/Resources/Strings.resx @@ -207,6 +207,9 @@ <data name="ExpectedValClassObjRefVariable" xml:space="preserve"> <value>Value type, ObjRef type or variable type expected.</value> </data> + <data name="FieldAccess" xml:space="preserve"> + <value>Field is not visible.</value> + </data> <data name="InitLocals" xml:space="preserve"> <value>initlocals must be set for verifiable methods with one or more local variables.</value> </data> @@ -219,6 +222,9 @@ <data name="LdvirtftnOnStatic" xml:space="preserve"> <value>ldvirtftn on static.</value> </data> + <data name="MethodAccess" xml:space="preserve"> + <value>Method is not visible.</value> + </data> <data name="PathStackDepth" xml:space="preserve"> <value>Stack depth differs depending on path.</value> </data> diff --git a/src/ILVerify/src/VerifierError.cs b/src/ILVerify/src/VerifierError.cs index 33862ef92..df2f02329 100644 --- a/src/ILVerify/src/VerifierError.cs +++ b/src/ILVerify/src/VerifierError.cs @@ -131,8 +131,8 @@ namespace ILVerify //E_ARGLIST "Allowed only in vararg methods." ValueTypeExpected, // Value type expected. //E_OPEN_DLGT_PROT_ACC "Protected method access through an open instance delegate is not verifiable." - //E_METHOD_ACCESS "Method is not visible." - //E_FIELD_ACCESS "Field is not visible." + MethodAccess, // Method is not visible. + FieldAccess, // Field is not visible. //E_DEAD "Item is unusable at this point." ExpectedStaticField, // Expected static field. //E_FIELD_NO_STATIC "Expected non-static field." diff --git a/src/ILVerify/tests/ILTests/AccessTests.il b/src/ILVerify/tests/ILTests/AccessTests.il new file mode 100644 index 000000000..9de153c3c --- /dev/null +++ b/src/ILVerify/tests/ILTests/AccessTests.il @@ -0,0 +1,398 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Runtime +{ +} + +.assembly extern AccessTestsFriend +{ +} + +.assembly AccessTests +{ +} + +.class private auto ansi beforefieldinit PrivateClass +{ + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + ldarg.0 + call instance void [System.Runtime]System.Object::.ctor() + ret + } +} + +.class public auto ansi beforefieldinit GenericClass<S, T> + extends [System.Runtime]System.Object +{ + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + ldarg.0 + call instance void [System.Runtime]System.Object::.ctor() + ret + } +} + +.class public auto ansi beforefieldinit SimpleClass + extends [System.Runtime]System.Object +{ + .field public static int32 publicField + .field private static int32 privateField + .field family static int32 familyField + .field assembly static int32 assemblyField + .field famorassem static int32 familyOrAssemblyField + .field famandassem static int32 familyAndAssemblyField + + .field family int32 instanceFamilyField + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + ldarg.0 + call instance void [System.Runtime]System.Object::.ctor() + ret + } + + .method private hidebysig static void PrivateMethod() cil managed + { + ret + } + + .method family hidebysig static void FamilyMethod() cil managed + { + ret + } + + .method assembly hidebysig static void AssemblyMethod() cil managed + { + ret + } + + .method famorassem hidebysig static void FamilyOrAssemblyMethod() cil managed + { + ret + } + + .method famandassem hidebysig static void FamilyAndAssemblyMethod() cil managed + { + ret + } + + .method public hidebysig static void InaccessibleParamMethod(class SimpleClass/PrivateNestedClass c) cil managed + { + ret + } + + .method public hidebysig static void GenericMethod<T>() cil managed + { + ret + } + + .method family hidebysig instance void FamilyMethod() cil managed + { + ret + } + + .method public hidebysig static class SimpleClass/PrivateNestedClass InaccessibleReturnMethod() cil managed + { + newobj instance void SimpleClass/PrivateNestedClass::.ctor() + ret + } + + .class nested public auto ansi beforefieldinit PublicNestedClass + extends [System.Runtime]System.Object + { + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + ldarg.0 + call instance void [System.Runtime]System.Object::.ctor() + ret + } + + .method public hidebysig static void Instantiate.PrivateNestedClassFromNested_Valid() cil managed + { + newobj instance void SimpleClass/PrivateNestedClass::.ctor() + pop + ret + } + + .method public hidebysig static void Load.PrivateFieldFromNestedClass_Valid() cil managed + { + ldsfld int32 SimpleClass::privateField + pop + ret + } + } + + .class nested private auto ansi beforefieldinit PrivateNestedClass + extends [System.Runtime]System.Object + { + .field public static int32 publicField + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + ldarg.0 + call instance void [System.Runtime]System.Object::.ctor() + ret + } + } + + .class nested assembly auto ansi beforefieldinit AssemblyNestedClass + extends [System.Runtime]System.Object + { + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + ldarg.0 + call instance void [System.Runtime]System.Object::.ctor() + ret + } + } + + .class nested famorassem auto ansi beforefieldinit FamilyOrAssemblyNestedClass + extends [System.Runtime]System.Object + { + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + ldarg.0 + call instance void [System.Runtime]System.Object::.ctor() + ret + } + } + + .class nested famandassem auto ansi beforefieldinit FamilyAndAssemblyNestedClass + extends [System.Runtime]System.Object + { + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + ldarg.0 + call instance void [System.Runtime]System.Object::.ctor() + ret + } + } + + .class nested family auto ansi beforefieldinit FamilyNestedClass + extends [System.Runtime]System.Object + { + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + ldarg.0 + call instance void [System.Runtime]System.Object::.ctor() + ret + } + } + + .method private hidebysig static void Call.PrivateClassParamIntern_Valid(class SimpleClass/PrivateNestedClass c) cil managed + { + ldarg.0 + call void SimpleClass::InaccessibleParamMethod(class SimpleClass/PrivateNestedClass) + ret + } + + .method private hidebysig static void Call.PrivateReturnTypeIntern_Valid() cil managed + { + call class SimpleClass/PrivateNestedClass SimpleClass::InaccessibleReturnMethod() + pop + ret + } +} + +.class public auto ansi beforefieldinit AccessTestsType + extends [System.Runtime]System.Object +{ + .method public hidebysig instance void Instantiate.PublicNestedClass_Valid() cil managed + { + newobj instance void SimpleClass/PublicNestedClass::.ctor() + pop + ret + } + + .method public hidebysig instance void Instantiate.PrivateNestedClass_Invalid_MethodAccess() cil managed + { + newobj instance void SimpleClass/PrivateNestedClass::.ctor() + pop + ret + } + + .method public hidebysig instance void Instantiate.AssemNestedClass_Valid() cil managed + { + newobj instance void SimpleClass/AssemblyNestedClass::.ctor() + pop + ret + } + + .method public hidebysig instance void Instantiate.AssemOrFamNestedClass_Valid() cil managed + { + newobj instance void SimpleClass/FamilyOrAssemblyNestedClass::.ctor() + pop + ret + } + + .method public hidebysig instance void Instantiate.AssemAndFamNestedClass_Invalid_MethodAccess() cil managed + { + newobj instance void SimpleClass/FamilyAndAssemblyNestedClass::.ctor() + pop + ret + } + + .method public hidebysig instance void Instantiate.FamilyNestedClass_Invalid_MethodAccess() cil managed + { + newobj instance void SimpleClass/FamilyNestedClass::.ctor() + pop + ret + } + + .method public hidebysig instance void Instantiate.GenericWithPrivateNestedClass_Invalid_MethodAccess() cil managed + { + newobj instance void class GenericClass<class SimpleClass/PrivateNestedClass, class SimpleClass/PublicNestedClass>::.ctor() + pop + ret + } + + .method public hidebysig instance void Call.PrivateClassParamExtern_Invalid_MethodAccess(class SimpleClass/PrivateNestedClass c) cil managed + { + ldarg.1 + call void SimpleClass::InaccessibleParamMethod(class SimpleClass/PrivateNestedClass) + ret + } + + .method public hidebysig instance void Call.PrivateReturnTypeExtern_Invalid_MethodAccess() cil managed + { + call class SimpleClass/PrivateNestedClass SimpleClass::InaccessibleReturnMethod() + pop + ret + } + + .method public hidebysig instance void Call.GenericMethodWithPrivateNestedClass_Invalid_MethodAccess() cil managed + { + call void class SimpleClass::GenericMethod<class SimpleClass/PrivateNestedClass>() + ret + } + + .method public hidebysig instance void Load.PrivateFieldExtern_Invalid_FieldAccess() cil managed + { + ldsfld int32 SimpleClass::privateField + pop + ret + } + + .method public hidebysig instance void Load.PublicFieldOfPrivateClass_Invalid_FieldAccess() cil managed + { + ldsfld int32 SimpleClass/PrivateNestedClass::publicField + pop + ret + } +} + +.class public auto ansi beforefieldinit DerivedType + extends SimpleClass +{ + .method public hidebysig instance void Call.DerivedFamAndAssemblyMethod_Valid() cil managed + { + call void SimpleClass::FamilyAndAssemblyMethod() + ret + } + + .method public hidebysig instance void Instantiate.FamOrAssemblyNestedClassFromDerived_Valid() cil managed + { + newobj instance void SimpleClass/FamilyOrAssemblyNestedClass::.ctor() + pop + ret + } + + .method public hidebysig instance void Instantiate.FamNestedClassFromDerived_Valid() cil managed + { + newobj instance void SimpleClass/FamilyNestedClass::.ctor() + pop + ret + } + + .method private hidebysig instance void Load.FamFieldOfBaseWithBaseInstance_Invalid_FieldAccess(class SimpleClass c) cil managed + { + ldarg.1 + ldfld int32 SimpleClass::instanceFamilyField + pop + ret + } + + .method private hidebysig instance void Load.FamFieldOfBaseWithDerivedInstance_Valid() cil managed + { + ldarg.0 + ldfld int32 SimpleClass::instanceFamilyField + pop + ret + } + + .method private hidebysig instance void Call.FamMethodOfBaseWithBaseInstance_Invalid_MethodAccess(class SimpleClass c) cil managed + { + ldarg.1 + call instance void SimpleClass::FamilyMethod() + ret + } + + .method private hidebysig instance void Call.FamMethodOfBaseWithDerivedInstance_Valid() cil managed + { + ldarg.0 + call instance void SimpleClass::FamilyMethod() + ret + } + + .method private hidebysig instance void Load.AssemFieldOfFriendAssembly_Valid() cil managed + { + ldsfld int32 [AccessTestsFriend]AccessTestsFriendType::assemblyField + pop + ret + } + + .method private hidebysig instance void Load.PrivateFieldOfFriendAssembly_Invalid_FieldAccess() cil managed + { + ldsfld int32 [AccessTestsFriend]AccessTestsFriendType::privateField + pop + ret + } +} + +// Special case: Nested class trying to access family field of superclass of containing class + +.class private auto ansi beforefieldinit SuperClass + extends [System.Runtime]System.Object +{ + .field family static int32 familyField + .field family int32 instanceFamilyField + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + ldarg.0 + call instance void [System.Runtime]System.Object::.ctor() + ret + } +} + +.class private auto ansi beforefieldinit NestedClass + extends SuperClass +{ + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + ldarg.0 + call instance void SuperClass::.ctor() + ret + } + + .class nested private auto ansi beforefieldinit NestedClass + extends [System.Runtime]System.Object + { + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + ldarg.0 + call instance void [System.Runtime]System.Object::.ctor() + ret + } + + .method private hidebysig instance void Load.FamFieldOfSuperOfContaining_Valid() cil managed + { + ldsfld int32 SuperClass::familyField + pop + ret + } + } +} diff --git a/src/ILVerify/tests/ILTests/AccessTestsExtern.il b/src/ILVerify/tests/ILTests/AccessTestsExtern.il new file mode 100644 index 000000000..31be7b663 --- /dev/null +++ b/src/ILVerify/tests/ILTests/AccessTestsExtern.il @@ -0,0 +1,152 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Runtime +{ +} + +.assembly extern AccessTests +{ +} + +.assembly AccessTestsExternal +{ +} + +.class public auto ansi beforefieldinit AccessTestsType + extends [System.Runtime]System.Object +{ + .method public hidebysig instance void Instantiate.PublicClass_Valid() cil managed + { + newobj instance void [AccessTests]SimpleClass::.ctor() + pop + ret + } + + .method public hidebysig instance void Instantiate.PrivateClass_Invalid_MethodAccess() cil managed + { + newobj instance void [AccessTests]PrivateClass::.ctor() + pop + ret + } + + .method public hidebysig instance void Instantiate.PublicNested_Valid() cil managed + { + newobj instance void [AccessTests]SimpleClass/PublicNestedClass::.ctor() + pop + ret + } + + .method public hidebysig instance void Instantiate.PrivateNested_Invalid_MethodAccess() cil managed + { + newobj instance void [AccessTests]SimpleClass/PrivateNestedClass::.ctor() + pop + ret + } + + .method public hidebysig instance void Instantiate.AssemblyNested_Invalid_MethodAccess() cil managed + { + newobj instance void [AccessTests]SimpleClass/AssemblyNestedClass::.ctor() + pop + ret + } + + .method public hidebysig instance void Instantiate.FamOrAssemNested_Invalid_MethodAccess() cil managed + { + newobj instance void [AccessTests]SimpleClass/FamilyOrAssemblyNestedClass::.ctor() + pop + ret + } + + .method public hidebysig instance void Instantiate.FamAndAssemNested_Invalid_MethodAccess() cil managed + { + newobj instance void [AccessTests]SimpleClass/FamilyAndAssemblyNestedClass::.ctor() + pop + ret + } + + .method public hidebysig instance void Instantiate.FamilyNested_Invalid_MethodAccess() cil managed + { + newobj instance void [AccessTests]SimpleClass/FamilyNestedClass::.ctor() + pop + ret + } + + .method public hidebysig instance void Call.PrivateMethod_Invalid_MethodAccess() cil managed + { + call void [AccessTests]SimpleClass::PrivateMethod() + ret + } + + .method public hidebysig instance void Call.FamilyMethod_Invalid_MethodAccess() cil managed + { + call void [AccessTests]SimpleClass::FamilyMethod() + ret + } + + .method public hidebysig instance void Call.AssemblyMethod_Invalid_MethodAccess() cil managed + { + call void [AccessTests]SimpleClass::AssemblyMethod() + ret + } + + .method public hidebysig instance void Call.FamOrAssemMethod_Invalid_MethodAccess() cil managed + { + call void [AccessTests]SimpleClass::FamilyOrAssemblyMethod() + ret + } + + .method public hidebysig instance void Call.FamAndAssemMethod_Invalid_MethodAccess() cil managed + { + call void [AccessTests]SimpleClass::FamilyAndAssemblyMethod() + ret + } +} + +.class public auto ansi beforefieldinit DerivedType + extends [AccessTests]SimpleClass +{ + .method public hidebysig instance void Call.DerivedFamMethod_Valid() cil managed + { + call void [AccessTests]SimpleClass::FamilyMethod() + ret + } + + .method public hidebysig instance void Call.DerivedFamOrAssemMethod_Valid() cil managed + { + call void [AccessTests]SimpleClass::FamilyOrAssemblyMethod() + ret + } + + .method public hidebysig instance void Call.DerivedFamAndAssemMethod_Invalid_MethodAccess() cil managed + { + call void [AccessTests]SimpleClass::FamilyAndAssemblyMethod() + ret + } +} + +.class public auto ansi beforefieldinit DerivedClass + extends [AccessTests]SimpleClass +{ + .method public hidebysig instance void Instantiate.FamAndAssemNestedClassFromDerived_Invalid_MethodAccess() cil managed + { + newobj instance void [AccessTests]SimpleClass/FamilyAndAssemblyNestedClass::.ctor() + pop + ret + } + + .method public hidebysig instance void Instantiate.FamOrAssemNestedClassFromDerived_Valid() cil managed + { + newobj instance void [AccessTests]SimpleClass/FamilyOrAssemblyNestedClass::.ctor() + pop + ret + } + + .method public hidebysig instance void Instantiate.FamNestedClassFromDerived_Valid() cil managed + { + newobj instance void [AccessTests]SimpleClass/FamilyNestedClass::.ctor() + pop + ret + } +} diff --git a/src/ILVerify/tests/ILTests/AccessTestsFriend.il b/src/ILVerify/tests/ILTests/AccessTestsFriend.il new file mode 100644 index 000000000..869470b62 --- /dev/null +++ b/src/ILVerify/tests/ILTests/AccessTestsFriend.il @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Runtime +{ +} + +.assembly extern AccessTests +{ +} + +.assembly AccessTestsFriend +{ + // InternalsVisibleTo("AccessTests") + .custom instance void [System.Runtime]System.Runtime.CompilerServices.InternalsVisibleToAttribute::.ctor(string) = ( + 01 00 0b 41 63 63 65 73 73 54 65 73 74 73 00 00 + ) +} + +.class private auto ansi beforefieldinit AccessTestsFriendType + extends [System.Runtime]System.Object +{ + .field private static int32 privateField + .field assembly static int32 assemblyField +} diff --git a/src/ILVerify/tests/TestDataLoader.cs b/src/ILVerify/tests/TestDataLoader.cs index d594aea12..15dc8efde 100644 --- a/src/ILVerify/tests/TestDataLoader.cs +++ b/src/ILVerify/tests/TestDataLoader.cs @@ -173,6 +173,10 @@ namespace ILVerify.Tests { systemRuntime.GetName().Name, systemRuntime.Location } }; + typeSystemContext.ReferenceFilePaths = new Dictionary<string, string>(); + foreach (var fileName in GetAllTestDlls()) + typeSystemContext.ReferenceFilePaths.Add(Path.GetFileNameWithoutExtension(fileName), TESTASSEMBLYPATH + fileName); + typeSystemContext.SetSystemModule(typeSystemContext.GetModuleForSimpleName(coreAssembly.GetName().Name)); return typeSystemContext.GetModuleFromPath(TESTASSEMBLYPATH + assemblyName); } |