Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -137,28 +137,24 @@ public static void Create_Using_BaseType_Without_Default_Ctor_Throws_ArgumentExc
}

[Fact]
[SkipOnMono("https://github.com/dotnet/runtime/issues/47989")]
public static void Create_Using_PrivateProxy()
{
Assert.NotNull(TestType_PrivateProxy.Proxy<TestType_IHelloService>());
}

[Fact]
[SkipOnMono("https://github.com/dotnet/runtime/issues/47989")]
public static void Create_Using_PrivateProxyAndInternalService()
{
Assert.NotNull(TestType_PrivateProxy.Proxy<TestType_InternalInterfaceService>());
}

[Fact]
[SkipOnMono("https://github.com/dotnet/runtime/issues/47989")]
public static void Create_Using_PrivateProxyAndInternalServiceWithExternalGenericArgument()
{
Assert.NotNull(TestType_PrivateProxy.Proxy<TestType_InternalInterfaceWithNonPublicExternalGenericArgument>());
}

[Fact]
[SkipOnMono("https://github.com/dotnet/runtime/issues/47989")]
public static void Create_Using_InternalProxy()
{
Assert.NotNull(DispatchProxy.Create<TestType_InternalInterfaceService, InternalInvokeProxy>());
Expand All @@ -171,7 +167,6 @@ public static void Create_Using_ExternalNonPublicService()
}

[Fact]
[SkipOnMono("https://github.com/dotnet/runtime/issues/47989")]
public static void Create_Using_InternalProxyWithExternalNonPublicBaseType()
{
Assert.NotNull(DispatchProxy.Create<TestType_IHelloService, TestType_InternalProxyInternalBaseType>());
Expand All @@ -190,7 +185,6 @@ public static void Create_Using_InternalServiceWithGenericArgumentBeingNonPublic
}

[Fact]
[SkipOnMono("https://github.com/dotnet/runtime/issues/47989")]
public static void Create_Using_InternalProxyWithBaseTypeImplementingServiceWithgenericArgumentBeingNonPublicExternalService()
{
Assert.NotNull(DispatchProxy.Create<TestType_IHelloService, TestType_InternalProxyImplementingInterfaceWithGenericArgumentBeingNonPublicExternalType>());
Expand Down
86 changes: 86 additions & 0 deletions src/libraries/System.Reflection.Emit/tests/AssemblyBuilderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -340,5 +340,91 @@ private static void VerifyAssemblyBuilder(AssemblyBuilder assembly, AssemblyName
Assert.Empty(assembly.DefinedTypes);
Assert.Empty(assembly.GetTypes());
}

private static void SamplePrivateMethod ()
{
}

internal static void SampleInternalMethod ()
{
}

[Fact]
void Invoke_Private_CrossAssembly_ThrowsMethodAccessException()
{
TypeBuilder tb = Helpers.DynamicType(TypeAttributes.Public);
var mb = tb.DefineMethod ("MyMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(void), new Type[] { });

var ilg = mb.GetILGenerator ();

var callee = typeof (AssemblyTests).GetMethod ("SamplePrivateMethod", BindingFlags.Static | BindingFlags.NonPublic);

ilg.Emit (OpCodes.Call, callee);
ilg.Emit (OpCodes.Ret);

var ty = tb.CreateType ();

var mi = ty.GetMethod ("MyMethod", BindingFlags.Static | BindingFlags.Public);

var d = (Action) mi.CreateDelegate (typeof(Action));

Assert.Throws<MethodAccessException>(() => d ());
}

[Fact]
void Invoke_Internal_CrossAssembly_ThrowsMethodAccessException()
{
TypeBuilder tb = Helpers.DynamicType(TypeAttributes.Public);
var mb = tb.DefineMethod ("MyMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(void), new Type[] { });

var ilg = mb.GetILGenerator ();

var callee = typeof (AssemblyTests).GetMethod ("SampleInternalMethod", BindingFlags.Static | BindingFlags.NonPublic);

ilg.Emit (OpCodes.Call, callee);
ilg.Emit (OpCodes.Ret);

var ty = tb.CreateType ();

var mi = ty.GetMethod ("MyMethod", BindingFlags.Static | BindingFlags.Public);

var d = (Action) mi.CreateDelegate (typeof(Action));

Assert.Throws<MethodAccessException>(() => d ());
}

[Fact]
void Invoke_Private_SameAssembly_ThrowsMethodAccessException()
{
ModuleBuilder modb = Helpers.DynamicModule();

string calleeName = "PrivateMethod";

TypeBuilder tbCalled = modb.DefineType ("CalledClass", TypeAttributes.Public);
var mbCalled = tbCalled.DefineMethod (calleeName, MethodAttributes.Private | MethodAttributes.Static);
mbCalled.GetILGenerator().Emit (OpCodes.Ret);

var tyCalled = tbCalled.CreateType();
var callee = tyCalled.GetMethod (calleeName, BindingFlags.NonPublic | BindingFlags.Static);

TypeBuilder tb = modb.DefineType("CallerClass", TypeAttributes.Public);
var mb = tb.DefineMethod ("MyMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(void), new Type[] { });

var ilg = mb.GetILGenerator ();

ilg.Emit (OpCodes.Call, callee);
ilg.Emit (OpCodes.Ret);

var ty = tb.CreateType ();

var mi = ty.GetMethod ("MyMethod", BindingFlags.Static | BindingFlags.Public);

var d = (Action) mi.CreateDelegate (typeof(Action));

Assert.Throws<MethodAccessException>(() => d ());
}



}
}
42 changes: 28 additions & 14 deletions src/mono/mono/metadata/assembly.c
Original file line number Diff line number Diff line change
Expand Up @@ -2080,8 +2080,9 @@ mono_assembly_request_open (const char *filename, const MonoAssemblyOpenRequest
}

static void
free_item (gpointer val, gpointer user_data)
free_assembly_name_item (gpointer val, gpointer user_data)
{
mono_assembly_name_free_internal ((MonoAssemblyName *)val);
g_free (val);
}

Expand All @@ -2105,7 +2106,6 @@ mono_assembly_load_friends (MonoAssembly* ass)
ERROR_DECL (error);
int i;
MonoCustomAttrInfo* attrs;
GSList *list;

if (ass->friend_assembly_names_inited)
return;
Expand All @@ -2126,7 +2126,9 @@ mono_assembly_load_friends (MonoAssembly* ass)
}
mono_assemblies_unlock ();

list = NULL;
GSList *visible_list = NULL;
GSList *ignores_list = NULL;

/*
* We build the list outside the assemblies lock, the worse that can happen
* is that we'll need to free the allocated list.
Expand All @@ -2138,7 +2140,16 @@ mono_assembly_load_friends (MonoAssembly* ass)
uint32_t data_length;
gchar *data_with_terminator;
/* Do some sanity checking */
if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
if (!attr->ctor)
continue;
gboolean has_visible = FALSE;
gboolean has_ignores = FALSE;
has_visible = attr->ctor->klass == mono_class_try_get_internals_visible_class ();
/* IgnoresAccessChecksToAttribute is dynamically generated, so it's not necessarily in CoreLib */
/* FIXME: should we only check for it in dynamic modules? */
has_ignores = (!strcmp ("IgnoresAccessChecksToAttribute", m_class_get_name (attr->ctor->klass)) &&
!strcmp ("System.Runtime.CompilerServices", m_class_get_name_space (attr->ctor->klass)));
if (!has_visible && !has_ignores)
continue;
if (attr->data_size < 4)
continue;
Expand All @@ -2152,7 +2163,10 @@ mono_assembly_load_friends (MonoAssembly* ass)
aname = g_new0 (MonoAssemblyName, 1);
/*g_print ("friend ass: %s\n", data);*/
if (mono_assembly_name_parse_full (data_with_terminator, aname, TRUE, NULL, NULL)) {
list = g_slist_prepend (list, aname);
if (has_visible)
visible_list = g_slist_prepend (visible_list, aname);
if (has_ignores)
ignores_list = g_slist_prepend (ignores_list, aname);
} else {
g_free (aname);
}
Expand All @@ -2163,11 +2177,14 @@ mono_assembly_load_friends (MonoAssembly* ass)
mono_assemblies_lock ();
if (ass->friend_assembly_names_inited) {
mono_assemblies_unlock ();
g_slist_foreach (list, free_item, NULL);
g_slist_free (list);
g_slist_foreach (visible_list, free_assembly_name_item, NULL);
g_slist_free (visible_list);
g_slist_foreach (ignores_list, free_assembly_name_item, NULL);
g_slist_free (ignores_list);
return;
}
ass->friend_assembly_names = list;
ass->friend_assembly_names = visible_list;
ass->ignores_checks_assembly_names = ignores_list;

/* Because of the double checked locking pattern above */
mono_memory_barrier ();
Expand Down Expand Up @@ -3318,7 +3335,6 @@ mono_assembly_release_gc_roots (MonoAssembly *assembly)
gboolean
mono_assembly_close_except_image_pools (MonoAssembly *assembly)
{
GSList *tmp;
g_return_val_if_fail (assembly != NULL, FALSE);

if (assembly == REFERENCE_MISSING)
Expand All @@ -3343,12 +3359,10 @@ mono_assembly_close_except_image_pools (MonoAssembly *assembly)
if (!mono_image_close_except_pools (assembly->image))
assembly->image = NULL;

for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
mono_assembly_name_free_internal (fname);
g_free (fname);
}
g_slist_foreach (assembly->friend_assembly_names, free_assembly_name_item, NULL);
g_slist_foreach (assembly->ignores_checks_assembly_names, free_assembly_name_item, NULL);
g_slist_free (assembly->friend_assembly_names);
g_slist_free (assembly->ignores_checks_assembly_names);
g_free (assembly->basedir);

MONO_PROFILER_RAISE (assembly_unloaded, (assembly));
Expand Down
25 changes: 22 additions & 3 deletions src/mono/mono/metadata/class.c
Original file line number Diff line number Diff line change
Expand Up @@ -5855,6 +5855,23 @@ is_valid_family_access (MonoClass *access_klass, MonoClass *member_klass, MonoCl
return TRUE;
}

static gboolean
ignores_access_checks_to (MonoAssembly *accessing, MonoAssembly *accessed)
{
if (!accessing || !accessed)
return FALSE;

mono_assembly_load_friends (accessing);
for (GSList *tmp = accessing->ignores_checks_assembly_names; tmp; tmp = tmp->next) {
MonoAssemblyName *victim = (MonoAssemblyName *)tmp->data;
if (!victim->name)
continue;
if (!g_ascii_strcasecmp (accessed->aname.name, victim->name))
return TRUE;
}
return FALSE;
}

static gboolean
can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed)
{
Expand All @@ -5880,7 +5897,7 @@ can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed)
}
return TRUE;
}
return FALSE;
return ignores_access_checks_to (accessing, accessed);
}

/*
Expand Down Expand Up @@ -5979,7 +5996,9 @@ can_access_type (MonoClass *access_klass, MonoClass *member_klass)
return member_klass_nested_in && can_access_type (access_klass, member_klass_nested_in);

case TYPE_ATTRIBUTE_NESTED_PRIVATE:
return is_nesting_type (member_klass, access_klass) && member_klass_nested_in && can_access_type (access_klass, member_klass_nested_in);
if (is_nesting_type (member_klass, access_klass) && member_klass_nested_in && can_access_type (access_klass, member_klass_nested_in))
return TRUE;
return ignores_access_checks_to (access_klass_assembly, member_klass_assembly);

case TYPE_ATTRIBUTE_NESTED_FAMILY:
return mono_class_has_parent_and_ignore_generics (access_klass, m_class_get_nested_in (member_klass));
Expand Down Expand Up @@ -6028,7 +6047,7 @@ can_access_member (MonoClass *access_klass, MonoClass *member_klass, MonoClass*
/* same compilation unit */
return m_class_get_image (access_klass) == member_klass_image;
case FIELD_ATTRIBUTE_PRIVATE:
return access_klass == member_klass;
return (access_klass == member_klass) || ignores_access_checks_to (access_klass_assembly, member_klass_image->assembly);
case FIELD_ATTRIBUTE_FAM_AND_ASSEM:
if (is_valid_family_access (access_klass, member_klass, context_klass) &&
can_access_internals (access_klass_assembly, member_klass_image->assembly))
Expand Down
1 change: 1 addition & 0 deletions src/mono/mono/metadata/metadata-internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ struct _MonoAssembly {
MonoAssemblyName aname;
MonoImage *image;
GSList *friend_assembly_names; /* Computed by mono_assembly_load_friends () */
GSList *ignores_checks_assembly_names; /* Computed by mono_assembly_load_friends () */
guint8 friend_assembly_names_inited;
guint8 dynamic;
MonoAssemblyContext context;
Expand Down