2009-03-21 Sebastien Pouliot <sebastien@ximian.com>
authorSebastien Pouliot <sebastien@ximian.com>
Sat, 21 Mar 2009 14:41:46 +0000 (14:41 -0000)
committerSebastien Pouliot <sebastien@ximian.com>
Sat, 21 Mar 2009 14:41:46 +0000 (14:41 -0000)
* exception.c|h: Add helpers to create [Field|Method]AccessException
* icall.c: Add required coreclr check calls for field reflection.
Move the existing (method) check logic into security-core-clr.c
* security-core-clr.c: Add functions to check if the access of a
field or method is allowed when reflecting under coreclr. This is
mostly done using a stack walk to find the "real" caller: i.e. the
code that is calling the reflection

svn path=/trunk/mono/; revision=129959

mono/metadata/ChangeLog
mono/metadata/exception.c
mono/metadata/exception.h
mono/metadata/icall.c
mono/metadata/security-core-clr.c
mono/metadata/security-core-clr.h

index 08de41a6814649ede1ab2fd8d9bc674f3e374337..f79eee28df097f96e087f20192efcdff8936ed78 100644 (file)
@@ -1,3 +1,13 @@
+2009-03-21  Sebastien Pouliot  <sebastien@ximian.com>
+
+       * exception.c|h: Add helpers to create [Field|Method]AccessException
+       * icall.c: Add required coreclr check calls for field reflection.
+       Move the existing (method) check logic into security-core-clr.c
+       * security-core-clr.c: Add functions to check if the access of a
+       field or method is allowed when reflecting under coreclr. This is
+       mostly done using a stack walk to find the "real" caller: i.e. the
+       code that is calling the reflection
+
 2009-03-20  Zoltan Varga  <vargaz@gmail.com>
 
        * gc-internal.h: Change location of gc_wrapper.h
index 7646208a5aa4021f8f77f1572d4e0b310b3de67f..2fe196762ebb8e37cb2dc08822996fbcb73a6d5a 100644 (file)
@@ -667,6 +667,28 @@ mono_get_exception_out_of_memory (void)
        return mono_exception_from_name (mono_get_corlib (), "System", "OutOfMemoryException");
 }
 
+/**
+ * mono_get_exception_field_access:
+ *
+ * Returns: a new instance of the System.FieldAccessException
+ */
+MonoException *
+mono_get_exception_field_access (void)
+{
+       return mono_exception_from_name (mono_get_corlib (), "System", "FieldAccessException");
+}
+
+/**
+ * mono_get_exception_method_access:
+ *
+ * Returns: a new instance of the System.MethodAccessException
+ */
+MonoException *
+mono_get_exception_method_access (void)
+{
+       return mono_exception_from_name (mono_get_corlib (), "System", "MethodAccessException");
+}
+
 /**
  * mono_get_exception_reflection_type_load:
  * @types: an array of types that were defined in the moduled loaded.
index 9deda389db72499e7e7ae2e6c38a2bc6ceaef70c..58fe1141600ba4b5b0a520e35ba8b928343192ef 100644 (file)
@@ -133,6 +133,12 @@ mono_get_exception_stack_overflow (void);
 MonoException *
 mono_get_exception_out_of_memory (void);
 
+MonoException *
+mono_get_exception_field_access (void);
+
+MonoException *
+mono_get_exception_method_access (void);
+
 MonoException *
 mono_get_exception_reflection_type_load (MonoArray *types, MonoArray *exceptions);
 
index e9d69114299b550274c3a0007fd9449548fe90f6..da84f77d2c30df3becb871b973aff7ba2d8adaed 100644 (file)
@@ -1702,6 +1702,9 @@ ves_icall_MonoField_GetValueInternal (MonoReflectionField *field, MonoObject *ob
                mono_raise_exception (mono_get_exception_invalid_operation (
                                        "It is illegal to get the value on a field on a type loaded using the ReflectionOnly methods."));
        
+       if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+               mono_security_core_clr_ensure_reflection_access_field (cf);
+
        mono_class_init (field->klass);
 
        if (cf->type->attrs & FIELD_ATTRIBUTE_STATIC)
@@ -1820,6 +1823,9 @@ ves_icall_MonoField_SetValueInternal (MonoReflectionField *field, MonoObject *ob
                mono_raise_exception (mono_get_exception_invalid_operation (
                                        "It is illegal to set the value on a field on a type loaded using the ReflectionOnly methods."));
 
+       if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+               mono_security_core_clr_ensure_reflection_access_field (cf);
+
        v = (gchar *) value;
        if (!cf->type->byref) {
                switch (cf->type->type) {
@@ -3050,35 +3056,6 @@ ves_icall_MonoMethod_GetGenericArguments (MonoReflectionMethod *method)
        return res;
 }
 
-static void
-ensure_reflection_security (void)
-{
-       MonoMethod *m = mono_method_get_last_managed ();
-
-       while (m) {
-               /*
-               g_print ("method %s.%s.%s in image %s\n",
-                       m->klass->name_space, m->klass->name, m->name, m->klass->image->name);
-               */
-
-               /* We stop at the first method which is not in
-                  System.Reflection or which is not in a platform
-                  image. */
-               if (strcmp (m->klass->name_space, "System.Reflection") != 0 ||
-                               !mono_security_core_clr_is_platform_image (m->klass->image)) {
-                       /* If the method is transparent we throw an exception. */
-                       if (mono_security_core_clr_method_level (m, TRUE) == MONO_SECURITY_CORE_CLR_TRANSPARENT ) {
-                               MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MethodAccessException", "Reflection called from transparent code");
-
-                               mono_raise_exception (ex);
-                       }
-                       return;
-               }
-
-               mono_stack_walk_no_il (get_caller, &m);
-       }
-}
-
 static MonoObject *
 ves_icall_InternalInvoke (MonoReflectionMethod *method, MonoObject *this, MonoArray *params, MonoException **exc) 
 {
@@ -3095,9 +3072,8 @@ ves_icall_InternalInvoke (MonoReflectionMethod *method, MonoObject *this, MonoAr
 
        *exc = NULL;
 
-       if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR &&
-                       mono_security_core_clr_method_level (m, TRUE) == MONO_SECURITY_CORE_CLR_CRITICAL)
-               ensure_reflection_security ();
+       if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+               mono_security_core_clr_ensure_reflection_access_method (m);
 
        if (!(m->flags & METHOD_ATTRIBUTE_STATIC)) {
                if (this) {
index 2db2604ba7122f5c6c3ce69f99daf55c1cb8174b..e5b167356e8a5a03a06f00eaaaaef07fe3010d4f 100644 (file)
@@ -12,6 +12,8 @@
 #include <mono/metadata/assembly.h>
 #include <mono/metadata/appdomain.h>
 #include <mono/metadata/verify-internals.h>
+#include <mono/metadata/object.h>
+#include <mono/metadata/exception.h>
 
 #include "security-core-clr.h"
 
@@ -43,6 +45,109 @@ security_safe_critical_attribute (void)
        return class;
 }
 
+static gboolean
+get_caller_no_reflection_related (MonoMethod *m, gint32 no, gint32 ilo, gboolean managed, gpointer data)
+{
+       MonoMethod **dest = data;
+       const char *ns;
+
+       /* skip unmanaged frames */
+       if (!managed)
+               return FALSE;
+
+       if (m->wrapper_type != MONO_WRAPPER_NONE)
+               return FALSE;
+
+       /* quick out (any namespace not starting with an 'S' */
+       ns = m->klass->name_space;
+       if (!ns || (*ns != 'S')) {
+               *dest = m;
+               return TRUE;
+       }
+
+       /* stop if the method is not part of platform code */
+       if (!mono_security_core_clr_is_platform_image (m->klass->image)) {
+               *dest = m;
+               return TRUE;
+       }
+
+       /* any number of calls inside System.Reflection are allowed */
+       if (strcmp (ns, "System.Reflection") == 0)
+               return FALSE;
+
+       /* any number of calls inside System.Reflection are allowed */
+       if (strcmp (ns, "System.Reflection.Emit") == 0)
+               return FALSE;
+
+       /* calls from System.Delegate are also possible and allowed */
+       if (strcmp (ns, "System") == 0) {
+               const char *kname = m->klass->name;
+               if ((*kname == 'D') && (strcmp (kname, "Delegate") == 0))
+                       return FALSE;
+               if ((*kname == 'M') && (strcmp (kname, "MulticastDelegate")) == 0)
+                       return FALSE;
+               if ((*kname == 'A') && (strcmp (kname, "Activator") == 0))
+                       return FALSE;
+       }
+
+       if (m == *dest) {
+               *dest = NULL;
+               return FALSE;
+       }
+
+       *dest = m;
+       return TRUE;
+}
+
+/* walk to the first managed method outside:
+ *  - System.Reflection* namespaces
+ *  - System.[MulticastDelegate]Delegate or Activator type
+ *  - platform code
+ *  and return its value, since CoreCLR checks needs to be done on this "real" caller.
+ */
+static MonoMethod*
+get_reflection_caller (void)
+{
+       MonoMethod *m = mono_method_get_last_managed ();
+       mono_stack_walk_no_il (get_caller_no_reflection_related, &m);
+       return m;
+}
+
+void
+mono_security_core_clr_ensure_reflection_access_field (MonoClassField *field)
+{
+       MonoClass *klass = mono_field_get_parent (field);
+
+       /* under CoreCLR you cannot use the value (get/set) of the reflected field: */
+       MonoMethod *caller = get_reflection_caller ();
+
+       /* (a) of a Critical type when called from a Transparent caller */
+       if (mono_security_core_clr_class_level (klass) == MONO_SECURITY_CORE_CLR_CRITICAL) {
+               if (mono_security_core_clr_method_level (caller, TRUE) == MONO_SECURITY_CORE_CLR_TRANSPARENT)
+                       mono_raise_exception (mono_get_exception_field_access ());
+       }
+       /* (b) that are not accessible from the caller pov */
+       if (!mono_method_can_access_field_full (caller, field, klass))
+               mono_raise_exception (mono_get_exception_field_access ());
+}
+
+void
+mono_security_core_clr_ensure_reflection_access_method (MonoMethod *method)
+{
+       MonoMethod *caller = get_reflection_caller ();
+       /* CoreCLR restrictions applies to Transparent code/caller */
+       if (mono_security_core_clr_method_level (caller, TRUE) != MONO_SECURITY_CORE_CLR_TRANSPARENT)
+               return;
+
+       /* Transparent code cannot invoke, even using reflection, Critical code */
+       if (mono_security_core_clr_method_level (method, TRUE) == MONO_SECURITY_CORE_CLR_CRITICAL)
+               mono_raise_exception (mono_get_exception_method_access ());
+
+       /* also it cannot invoke a method that is not visible from it's (caller) point of view */
+       if (!mono_method_can_access_method_full (caller, method, (method->flags & METHOD_ATTRIBUTE_STATIC) ? NULL : method->klass))
+               mono_raise_exception (mono_get_exception_method_access ());
+}
+
 static MonoSecurityCoreCLRLevel
 mono_security_core_clr_level_from_cinfo (MonoCustomAttrInfo *cinfo, MonoImage *image)
 {
index 025761d4123d1a150489443c303713bb3066d4b8..1e79579f19be73118b183fb35e580d01840841cd 100644 (file)
@@ -22,6 +22,9 @@ typedef enum {
 
 extern gboolean mono_security_core_clr_test;
 
+extern void mono_security_core_clr_ensure_reflection_access_field (MonoClassField *field) MONO_INTERNAL;
+extern void mono_security_core_clr_ensure_reflection_access_method (MonoMethod *method) MONO_INTERNAL;
+
 extern MonoSecurityCoreCLRLevel mono_security_core_clr_class_level (MonoClass *class) MONO_INTERNAL;
 extern MonoSecurityCoreCLRLevel mono_security_core_clr_method_level (MonoMethod *method, gboolean with_class_level) MONO_INTERNAL;