Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mono / metadata / security-core-clr.c
1 /**
2  * \file
3  * CoreCLR security
4  *
5  * Authors:
6  *      Mark Probst <mark.probst@gmail.com>
7  *      Sebastien Pouliot  <sebastien@ximian.com>
8  *
9  * Copyright 2007-2010 Novell, Inc (http://www.novell.com)
10  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
11  */
12
13 #include <mono/metadata/class-internals.h>
14 #include <mono/metadata/security-manager.h>
15 #include <mono/metadata/assembly.h>
16 #include <mono/metadata/appdomain.h>
17 #include <mono/metadata/verify-internals.h>
18 #include <mono/metadata/object.h>
19 #include <mono/metadata/exception.h>
20 #include <mono/metadata/debug-helpers.h>
21 #include <mono/utils/mono-logger-internals.h>
22
23 #include "security-core-clr.h"
24
25 gboolean mono_security_core_clr_test = FALSE;
26
27 static MonoSecurityCoreCLROptions security_core_clr_options = MONO_SECURITY_CORE_CLR_OPTIONS_DEFAULT;
28
29 /**
30  * mono_security_core_clr_set_options:
31  * \param options the new options for the coreclr system to use
32  *
33  * By default, the CoreCLRs security model forbids execution trough reflection of methods not visible from the calling code.
34  * Even if the method being called is not in a platform assembly. For non moonlight CoreCLR users this restriction does not
35  * make a lot of sense, since the author could have just changed the non platform assembly to allow the method to be called.
36  * This function allows specific relaxations from the default behaviour to be set.
37  *
38  * Use \c MONO_SECURITY_CORE_CLR_OPTIONS_DEFAULT for the default coreclr coreclr behaviour as used in Moonlight.
39  *
40  * Use \c MONO_SECURITY_CORE_CLR_OPTIONS_RELAX_REFLECTION to allow transparent code to execute methods and access 
41  * fields that are not in platformcode, even if those methods and fields are private or otherwise not visible to the calling code.
42  *
43  * Use \c MONO_SECURITY_CORE_CLR_OPTIONS_RELAX_DELEGATE to allow delegates to be created that point at methods that are not in
44  * platformcode even if those methods and fields are private or otherwise not visible to the calling code.
45  *
46  */
47 void
48 mono_security_core_clr_set_options (MonoSecurityCoreCLROptions options) {
49         security_core_clr_options = options;
50 }
51
52 /**
53  * mono_security_core_clr_get_options:
54  *
55  * Retrieves the current options used by the coreclr system.
56  */
57
58 MonoSecurityCoreCLROptions
59 mono_security_core_clr_get_options ()
60 {
61         return security_core_clr_options;
62 }
63
64 /*
65  * default_platform_check:
66  *
67  *      Default platform check. Always TRUE for current corlib (minimum 
68  *      trust-able subset) otherwise return FALSE. Any real CoreCLR host
69  *      should provide its own callback to define platform code (i.e.
70  *      this default is meant for test only).
71  */
72 static gboolean
73 default_platform_check (const char *image_name)
74 {
75         if (mono_defaults.corlib) {
76                 return (strcmp (mono_defaults.corlib->name, image_name) == 0);
77         } else {
78                 /* this can get called even before we load corlib (e.g. the EXE itself) */
79                 const char *corlib = "mscorlib.dll";
80                 int ilen = strlen (image_name);
81                 int clen = strlen (corlib);
82                 return ((ilen >= clen) && (strcmp ("mscorlib.dll", image_name + ilen - clen) == 0));
83         }
84 }
85
86 static MonoCoreClrPlatformCB platform_callback = default_platform_check;
87
88 /*
89  * mono_security_core_clr_determine_platform_image:
90  *
91  *  Call the supplied callback (from mono_security_set_core_clr_platform_callback) 
92  *  to determine if this image represents platform code.
93  */
94 gboolean
95 mono_security_core_clr_determine_platform_image (MonoImage *image)
96 {
97         return platform_callback (image->name);
98 }
99
100 /*
101  * mono_security_set_core_clr_platform_callback:
102  *
103  *  Set the callback function that will be used to determine if an image
104  *  is part, or not, of the platform code.
105  */
106 void
107 mono_security_set_core_clr_platform_callback (MonoCoreClrPlatformCB callback)
108 {
109         platform_callback = callback;
110 }
111
112 /*
113  * mono_security_core_clr_is_platform_image:
114  *
115  *   Return the (cached) boolean value indicating if this image represent platform code
116  */
117 gboolean
118 mono_security_core_clr_is_platform_image (MonoImage *image)
119 {
120         return image->core_clr_platform_code;
121 }
122
123 /* Note: The above functions are outside this guard so that the public API isn't affected. */
124
125 #ifndef DISABLE_SECURITY
126
127 /* Class lazy loading functions */
128 static GENERATE_GET_CLASS_WITH_CACHE (security_critical, "System.Security", "SecurityCriticalAttribute")
129 static GENERATE_GET_CLASS_WITH_CACHE (security_safe_critical, "System.Security", "SecuritySafeCriticalAttribute")
130
131 static MonoClass*
132 security_critical_attribute (void)
133 {
134         return mono_class_get_security_critical_class ();
135 }
136
137 static MonoClass*
138 security_safe_critical_attribute (void)
139 {
140         return mono_class_get_security_safe_critical_class ();
141
142 }
143
144 /* sometime we get a NULL (not found) caller (e.g. get_reflection_caller) */
145 static char*
146 get_method_full_name (MonoMethod * method)
147 {
148         return method ? mono_method_full_name (method, TRUE) : g_strdup ("'no caller found'");
149 }
150
151 /*
152  * set_type_load_exception_type
153  *
154  *      Set MONO_EXCEPTION_TYPE_LOAD on the specified 'class' and provide
155  *      a descriptive message for the exception. This message is also, 
156  *      optionally, being logged (export MONO_LOG_MASK="security") for
157  *      debugging purposes.
158  */
159 static void
160 set_type_load_exception_type (const char *format, MonoClass *klass)
161 {
162         char *type_name = mono_type_get_full_name (klass);
163         char *parent_name = mono_type_get_full_name (klass->parent);
164         char *message = mono_image_strdup_printf (klass->image, format, type_name, parent_name);
165
166         g_free (parent_name);
167         g_free (type_name);
168         
169         mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_SECURITY, "%s", message);
170         mono_class_set_type_load_failure (klass, "%s", message);
171         // note: do not free string given to mono_class_set_failure
172 }
173
174 /*
175  * set_type_load_exception_methods
176  *
177  *      Set MONO_EXCEPTION_TYPE_LOAD on the 'override' class and provide
178  *      a descriptive message for the exception. This message is also, 
179  *      optionally, being logged (export MONO_LOG_MASK="security") for
180  *      debugging purposes.
181  */
182 static void
183 set_type_load_exception_methods (const char *format, MonoMethod *override, MonoMethod *base)
184 {
185         char *method_name = get_method_full_name (override);
186         char *base_name = get_method_full_name (base);
187         char *message = mono_image_strdup_printf (override->klass->image, format, method_name, base_name);
188
189         g_free (base_name);
190         g_free (method_name);
191
192         mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_SECURITY, "%s", message);
193         mono_class_set_type_load_failure (override->klass, "%s", message);
194         // note: do not free string given to mono_class_set_failure
195 }
196
197 /* MonoClass is not fully initialized (inited is not yet == 1) when we 
198  * check the inheritance rules so we need to look for the default ctor
199  * ourselve to avoid recursion (and aborting)
200  */
201 static MonoMethod*
202 get_default_ctor (MonoClass *klass)
203 {
204         int i;
205
206         mono_class_setup_methods (klass);
207         if (!klass->methods)
208                 return NULL;
209
210         int mcount = mono_class_get_method_count (klass);
211         for (i = 0; i < mcount; ++i) {
212                 MonoMethodSignature *sig;
213                 MonoMethod *method = klass->methods [i];
214
215                 if (!method)
216                         continue;
217
218                 if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) == 0)
219                         continue;
220                 if ((method->name[0] != '.') || strcmp (".ctor", method->name))
221                         continue;
222                 sig = mono_method_signature (method);
223                 if (sig && (sig->param_count == 0))
224                         return method;
225         }
226
227         return NULL;
228 }
229
230 /*
231  * mono_security_core_clr_check_inheritance:
232  *
233  *      Determine if the specified class can inherit from its parent using 
234  *      the CoreCLR inheritance rules.
235  *
236  *      Base Type       Allow Derived Type
237  *      ------------    ------------------
238  *      Transparent     Transparent, SafeCritical, Critical
239  *      SafeCritical    SafeCritical, Critical
240  *      Critical        Critical
241  *
242  *      Reference: http://msdn.microsoft.com/en-us/magazine/cc765416.aspx#id0190030
243  *
244  *      Furthermore a class MUST have a default constructor if its base 
245  *      class has a non-transparent, public or protected, default constructor. 
246  *      The same inheritance rule applies to both default constructors.
247  *
248  *      Reference: message from a SecurityException in SL4RC
249  *      Reference: fxcop CA2132 rule
250  */
251 void
252 mono_security_core_clr_check_inheritance (MonoClass *klass)
253 {
254         MonoSecurityCoreCLRLevel class_level, parent_level;
255         MonoClass *parent = klass->parent;
256
257         if (!parent)
258                 return;
259
260         class_level = mono_security_core_clr_class_level (klass);
261         parent_level = mono_security_core_clr_class_level (parent);
262
263         if (class_level < parent_level) {
264                 set_type_load_exception_type (
265                         "Inheritance failure for type %s. Parent class %s is more restricted.",
266                         klass);
267         } else {
268                 MonoMethod *parent_ctor = get_default_ctor (parent);
269                 if (parent_ctor && ((parent_ctor->flags & METHOD_ATTRIBUTE_PUBLIC) != 0)) {
270                         class_level = mono_security_core_clr_method_level (get_default_ctor (klass), FALSE);
271                         parent_level = mono_security_core_clr_method_level (parent_ctor, FALSE);
272                         if (class_level < parent_level) {
273                                 set_type_load_exception_type (
274                                         "Inheritance failure for type %s. Default constructor security mismatch with %s.",
275                                         klass);
276                         }
277                 }
278         }
279 }
280
281 /*
282  * mono_security_core_clr_check_override:
283  *
284  *      Determine if the specified override can "legally" override the 
285  *      specified base method using the CoreCLR inheritance rules.
286  *
287  *      Base (virtual/interface)        Allowed override
288  *      ------------------------        -------------------------
289  *      Transparent                     Transparent, SafeCritical
290  *      SafeCritical                    Transparent, SafeCritical
291  *      Critical                        Critical
292  *
293  *      Reference: http://msdn.microsoft.com/en-us/magazine/cc765416.aspx#id0190030
294  */
295 void
296 mono_security_core_clr_check_override (MonoClass *klass, MonoMethod *override, MonoMethod *base)
297 {
298         MonoSecurityCoreCLRLevel base_level = mono_security_core_clr_method_level (base, FALSE);
299         MonoSecurityCoreCLRLevel override_level = mono_security_core_clr_method_level (override, FALSE);
300         /* if the base method is decorated with [SecurityCritical] then the overrided method MUST be too */
301         if (base_level == MONO_SECURITY_CORE_CLR_CRITICAL) {
302                 if (override_level != MONO_SECURITY_CORE_CLR_CRITICAL) {
303                         set_type_load_exception_methods (
304                                 "Override failure for %s over %s. Override MUST be [SecurityCritical].",
305                                 override, base);
306                 }
307         } else {
308                 /* base is [SecuritySafeCritical] or [SecurityTransparent], override MUST NOT be [SecurityCritical] */
309                 if (override_level == MONO_SECURITY_CORE_CLR_CRITICAL) {
310                         set_type_load_exception_methods (
311                                 "Override failure for %s over %s. Override must NOT be [SecurityCritical].", 
312                                 override, base);
313                 }
314         }
315 }
316
317 /*
318  * get_caller_no_reflection_related:
319  *
320  *      Find the first managed caller that is either:
321  *      (a) located outside the platform code assemblies; or
322  *      (b) not related to reflection and delegates
323  *
324  *      Returns TRUE to stop the stackwalk, FALSE to continue to the next frame.
325  */
326 static gboolean
327 get_caller_no_reflection_related (MonoMethod *m, gint32 no, gint32 ilo, gboolean managed, gpointer data)
328 {
329         MonoMethod **dest = (MonoMethod **)data;
330         const char *ns;
331
332         /* skip unmanaged frames */
333         if (!managed)
334                 return FALSE;
335
336         if (m->wrapper_type != MONO_WRAPPER_NONE)
337                 return FALSE;
338
339         /* quick out (any namespace not starting with an 'S' */
340         ns = m->klass->name_space;
341         if (!ns || (*ns != 'S')) {
342                 *dest = m;
343                 return TRUE;
344         }
345
346         /* stop if the method is not part of platform code */
347         if (!mono_security_core_clr_is_platform_image (m->klass->image)) {
348                 *dest = m;
349                 return TRUE;
350         }
351
352         /* any number of calls inside System.Reflection are allowed */
353         if (strcmp (ns, "System.Reflection") == 0)
354                 return FALSE;
355
356         /* any number of calls inside System.Reflection are allowed */
357         if (strcmp (ns, "System.Reflection.Emit") == 0)
358                 return FALSE;
359
360         /* calls from System.Delegate are also possible and allowed */
361         if (strcmp (ns, "System") == 0) {
362                 const char *kname = m->klass->name;
363                 if ((*kname == 'A') && (strcmp (kname, "Activator") == 0))
364                         return FALSE;
365
366                 /* unlike most Invoke* cases InvokeMember is not inside System.Reflection[.Emit] but is SecuritySafeCritical */
367                 if (((*kname == 'T') && (strcmp (kname, "Type") == 0)) || 
368                         ((*kname == 'R') && (strcmp (kname, "RuntimeType")) == 0)) {
369
370                         /* if calling InvokeMember then we can't stop the stackwalk here and need to look at the caller */
371                         if (strcmp (m->name, "InvokeMember") == 0)
372                                 return FALSE;
373                 }
374
375                 /* the security check on the delegate is made at creation time, not at invoke time */
376                 if (((*kname == 'D') && (strcmp (kname, "Delegate") == 0)) || 
377                         ((*kname == 'M') && (strcmp (kname, "MulticastDelegate")) == 0)) {
378
379                         /* if we're invoking then we can stop our stack walk */
380                         if (strcmp (m->name, "DynamicInvoke") != 0)
381                                 return FALSE;
382                 }
383         }
384
385         if (m == *dest) {
386                 *dest = NULL;
387                 return FALSE;
388         }
389
390         *dest = m;
391         return TRUE;
392 }
393
394 /*
395  * get_reflection_caller:
396  * 
397  *      Walk to the first managed method outside:
398  *      - System.Reflection* namespaces
399  *      - System.[Multicast]Delegate or Activator type
400  *      - platform code
401  *      and return a pointer to its MonoMethod.
402  *
403  *      This is required since CoreCLR checks needs to be done on this "real" caller.
404  */
405 static MonoMethod*
406 get_reflection_caller (void)
407 {
408         MonoMethod *m = NULL;
409         mono_stack_walk_no_il (get_caller_no_reflection_related, &m);
410         if (G_UNLIKELY (!m)) {
411                 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_SECURITY, "No caller outside reflection was found");
412         }
413         return m;
414 }
415
416 typedef struct {
417         int depth;
418         MonoMethod *caller;
419 } ElevatedTrustCookie;
420
421 /*
422  * get_caller_of_elevated_trust_code
423  *
424  *      Stack walk to find who is calling code requiring Elevated Trust.
425  *      If a critical method is found then the caller is platform code
426  *      and has elevated trust, otherwise (transparent) a check needs to
427  *      be done (on the managed side) to determine if the application is
428  *      running with elevated permissions.
429  */
430 static gboolean
431 get_caller_of_elevated_trust_code (MonoMethod *m, gint32 no, gint32 ilo, gboolean managed, gpointer data)
432 {
433         ElevatedTrustCookie *cookie = (ElevatedTrustCookie *)data;
434
435         /* skip unmanaged frames and wrappers */
436         if (!managed || (m->wrapper_type != MONO_WRAPPER_NONE))
437                 return FALSE;
438
439         /* end stack walk if we find ourselves outside platform code (we won't find critical code anymore) */
440         if (!mono_security_core_clr_is_platform_image (m->klass->image)) {
441                 cookie->caller = m;
442                 return TRUE;
443         }
444
445         switch (cookie->depth) {
446         /* while depth == 0 look for SecurityManager::[Check|Ensure]ElevatedPermissions */
447         case 0:
448                 if (strcmp (m->klass->name_space, "System.Security"))
449                         return FALSE;
450                 if (strcmp (m->klass->name, "SecurityManager"))
451                         return FALSE;
452                 if ((strcmp (m->name, "EnsureElevatedPermissions")) && strcmp (m->name, "CheckElevatedPermissions"))
453                         return FALSE;
454                 cookie->depth = 1;
455                 break;
456         /* while depth == 1 look for the caller to SecurityManager::[Check|Ensure]ElevatedPermissions */
457         case 1:
458                 /* this frame is [SecuritySafeCritical] because it calls [SecurityCritical] [Check|Ensure]ElevatedPermissions */
459                 /* the next frame will contain the caller(s) we want to check */
460                 cookie->depth = 2;
461                 break;
462         /* while depth >= 2 look for [safe]critical caller, end stack walk if we find it  */
463         default:
464                 cookie->depth++;
465                 /* if the caller is transparent then we continue the stack walk */
466                 if (mono_security_core_clr_method_level (m, TRUE) == MONO_SECURITY_CORE_CLR_TRANSPARENT)
467                         break;
468
469                 /* Security[Safe]Critical code is always allowed to call elevated-trust code */
470                 cookie->caller = m;
471                 return TRUE;
472         }
473
474         return FALSE;
475 }
476
477 /*
478  * mono_security_core_clr_require_elevated_permissions:
479  *
480  *      Return TRUE if the caller of the current method (the code who 
481  *      called SecurityManager.get_RequiresElevatedPermissions) needs
482  *      elevated trust to perform an action.
483  *
484  *      A stack walk is done to find the callers. If one of the callers
485  *      is either [SecurityCritical] or [SecuritySafeCritical] then the
486  *      action is needed for platform code (i.e. no restriction). 
487  *      Otherwise (transparent) the requested action needs elevated trust
488  */
489 gboolean
490 mono_security_core_clr_require_elevated_permissions (void)
491 {
492         ElevatedTrustCookie cookie;
493         cookie.depth = 0;
494         cookie.caller = NULL;
495         mono_stack_walk_no_il (get_caller_of_elevated_trust_code, &cookie);
496
497         /* return TRUE if the stack walk did not reach far enough or did not find callers */
498         if (!cookie.caller || cookie.depth < 3)
499                 return TRUE;
500
501         /* return TRUE if the caller is transparent, i.e. if elevated trust is required to continue executing the method */
502         return (mono_security_core_clr_method_level (cookie.caller, TRUE) == MONO_SECURITY_CORE_CLR_TRANSPARENT);
503 }
504
505
506 /*
507  * check_field_access:
508  *
509  *      Return TRUE if the caller method can access the specified field, FALSE otherwise.
510  */
511 static gboolean
512 check_field_access (MonoMethod *caller, MonoClassField *field)
513 {
514         /* if get_reflection_caller returns NULL then we assume the caller has NO privilege */
515         if (caller) {
516                 MonoError error;
517                 MonoClass *klass;
518
519                 /* this check can occur before the field's type is resolved (and that can fail) */
520                 mono_field_get_type_checked (field, &error);
521                 if (!mono_error_ok (&error)) {
522                         mono_error_cleanup (&error);
523                         return FALSE;
524                 }
525
526                 klass = (mono_field_get_flags (field) & FIELD_ATTRIBUTE_STATIC) ? NULL : mono_field_get_parent (field);
527                 return mono_method_can_access_field_full (caller, field, klass);
528         }
529         return FALSE;
530 }
531
532 /*
533  * check_method_access:
534  *
535  *      Return TRUE if the caller method can access the specified callee method, FALSE otherwise.
536  */
537 static gboolean
538 check_method_access (MonoMethod *caller, MonoMethod *callee)
539 {
540         /* if get_reflection_caller returns NULL then we assume the caller has NO privilege */
541         if (caller) {
542                 MonoClass *klass = (callee->flags & METHOD_ATTRIBUTE_STATIC) ? NULL : callee->klass;
543                 return mono_method_can_access_method_full (caller, callee, klass);
544         }
545         return FALSE;
546 }
547
548 /*
549  * get_argument_exception
550  *
551  *      Helper function to create an MonoException (ArgumentException in
552  *      managed-land) and provide a descriptive message for it. This 
553  *      message is also, optionally, being logged (export 
554  *      MONO_LOG_MASK="security") for debugging purposes.
555  */
556 static MonoException*
557 get_argument_exception (const char *format, MonoMethod *caller, MonoMethod *callee)
558 {
559         MonoException *ex;
560         char *caller_name = get_method_full_name (caller);
561         char *callee_name = get_method_full_name (callee);
562         char *message = g_strdup_printf (format, caller_name, callee_name);
563         g_free (callee_name);
564         g_free (caller_name);
565
566         mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_SECURITY, "%s", message);
567         ex = mono_get_exception_argument ("method", message);
568         g_free (message);
569
570         return ex;
571 }
572
573 /*
574  * get_field_access_exception
575  *
576  *      Helper function to create an MonoException (FieldAccessException
577  *      in managed-land) and provide a descriptive message for it. This
578  *      message is also, optionally, being logged (export 
579  *      MONO_LOG_MASK="security") for debugging purposes.
580  */
581 static MonoException*
582 get_field_access_exception (const char *format, MonoMethod *caller, MonoClassField *field)
583 {
584         MonoException *ex;
585         char *caller_name = get_method_full_name (caller);
586         char *field_name = mono_field_full_name (field);
587         char *message = g_strdup_printf (format, caller_name, field_name);
588         g_free (field_name);
589         g_free (caller_name);
590
591         mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_SECURITY, "%s", message);
592         ex = mono_get_exception_field_access_msg (message);
593         g_free (message);
594
595         return ex;
596 }
597
598 /*
599  * get_method_access_exception
600  *
601  *      Helper function to create an MonoException (MethodAccessException
602  *      in managed-land) and provide a descriptive message for it. This
603  *      message is also, optionally, being logged (export 
604  *      MONO_LOG_MASK="security") for debugging purposes.
605  */
606 static MonoException*
607 get_method_access_exception (const char *format, MonoMethod *caller, MonoMethod *callee)
608 {
609         MonoException *ex;
610         char *caller_name = get_method_full_name (caller);
611         char *callee_name = get_method_full_name (callee);
612         char *message = g_strdup_printf (format, caller_name, callee_name);
613         g_free (callee_name);
614         g_free (caller_name);
615
616         mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_SECURITY, "%s", message);
617         ex = mono_get_exception_method_access_msg (message);
618         g_free (message);
619
620         return ex;
621 }
622
623 /*
624  * mono_security_core_clr_ensure_reflection_access_field:
625  *
626  *      Ensure that the specified field can be used with reflection since 
627  *      Transparent code cannot access to Critical fields and can only use
628  *      them if they are visible from it's point of view.
629  *
630  *      Returns TRUE if acess is allowed.  Otherwise returns FALSE and sets @error to a FieldAccessException if the field is cannot be accessed.
631  */
632 gboolean
633 mono_security_core_clr_ensure_reflection_access_field (MonoClassField *field, MonoError *error)
634 {
635         error_init (error);
636         MonoMethod *caller = get_reflection_caller ();
637         /* CoreCLR restrictions applies to Transparent code/caller */
638         if (mono_security_core_clr_method_level (caller, TRUE) != MONO_SECURITY_CORE_CLR_TRANSPARENT)
639                 return TRUE;
640
641         if (mono_security_core_clr_get_options () & MONO_SECURITY_CORE_CLR_OPTIONS_RELAX_REFLECTION) {
642                 if (!mono_security_core_clr_is_platform_image (mono_field_get_parent(field)->image))
643                         return TRUE;
644         }
645
646         /* Transparent code cannot [get|set]value on Critical fields */
647         if (mono_security_core_clr_class_level (mono_field_get_parent (field)) == MONO_SECURITY_CORE_CLR_CRITICAL) {
648                 mono_error_set_exception_instance (error, get_field_access_exception (
649                         "Transparent method %s cannot get or set Critical field %s.", 
650                         caller, field));
651                 return FALSE;
652         }
653
654         /* also it cannot access a fields that is not visible from it's (caller) point of view */
655         if (!check_field_access (caller, field)) {
656                 mono_error_set_exception_instance (error, get_field_access_exception (
657                         "Transparent method %s cannot get or set private/internal field %s.", 
658                         caller, field));
659                 return FALSE;
660         }
661         return TRUE;
662 }
663
664 /*
665  * mono_security_core_clr_ensure_reflection_access_method:
666  *
667  *      Ensure that the specified method can be used with reflection since
668  *      Transparent code cannot call Critical methods and can only call them
669  *      if they are visible from it's point of view.
670  *
671  *      If access is allowed returns TRUE.  Returns FALSE and sets @error to a MethodAccessException if the field is cannot be accessed.
672  */
673 gboolean
674 mono_security_core_clr_ensure_reflection_access_method (MonoMethod *method, MonoError *error)
675 {
676         error_init (error);
677         MonoMethod *caller = get_reflection_caller ();
678         /* CoreCLR restrictions applies to Transparent code/caller */
679         if (mono_security_core_clr_method_level (caller, TRUE) != MONO_SECURITY_CORE_CLR_TRANSPARENT)
680                 return TRUE;
681
682         if (mono_security_core_clr_get_options () & MONO_SECURITY_CORE_CLR_OPTIONS_RELAX_REFLECTION) {
683                 if (!mono_security_core_clr_is_platform_image (method->klass->image))
684                         return TRUE;
685         }
686
687         /* Transparent code cannot invoke, even using reflection, Critical code */
688         if (mono_security_core_clr_method_level (method, TRUE) == MONO_SECURITY_CORE_CLR_CRITICAL) {
689                 mono_error_set_exception_instance (error, get_method_access_exception (
690                         "Transparent method %s cannot invoke Critical method %s.", 
691                         caller, method));
692                 return FALSE;
693         }
694
695         /* also it cannot invoke a method that is not visible from it's (caller) point of view */
696         if (!check_method_access (caller, method)) {
697                 mono_error_set_exception_instance (error, get_method_access_exception (
698                         "Transparent method %s cannot invoke private/internal method %s.", 
699                         caller, method));
700                 return FALSE;
701         }
702         return TRUE;
703 }
704
705 /*
706  * can_avoid_corlib_reflection_delegate_optimization:
707  *
708  *      Mono's mscorlib use delegates to optimize PropertyInfo and EventInfo
709  *      reflection calls. This requires either a bunch of additional, and not
710  *      really required, [SecuritySafeCritical] in the class libraries or 
711  *      (like this) a way to skip them. As a bonus we also avoid the stack
712  *      walk to find the caller.
713  *
714  *      Return TRUE if we can skip this "internal" delegate creation, FALSE
715  *      otherwise.
716  */
717 static gboolean
718 can_avoid_corlib_reflection_delegate_optimization (MonoMethod *method)
719 {
720         if (!mono_security_core_clr_is_platform_image (method->klass->image))
721                 return FALSE;
722
723         if (strcmp (method->klass->name_space, "System.Reflection") != 0)
724                 return FALSE;
725
726         if (strcmp (method->klass->name, "MonoProperty") == 0) {
727                 if ((strcmp (method->name, "GetterAdapterFrame") == 0) || strcmp (method->name, "StaticGetterAdapterFrame") == 0)
728                         return TRUE;
729         } else if (strcmp (method->klass->name, "EventInfo") == 0) {
730                 if ((strcmp (method->name, "AddEventFrame") == 0) || strcmp (method->name, "StaticAddEventAdapterFrame") == 0)
731                         return TRUE;
732         }
733
734         return FALSE;
735 }
736
737 /*
738  * mono_security_core_clr_ensure_delegate_creation:
739  *
740  *      Return TRUE if a delegate can be created on the specified
741  *      method.  CoreCLR can also affect the binding, this function may
742  *      return (FALSE) and set @error to an ArgumentException.
743  *
744  *      @error is set to a MethodAccessException if the specified method is not
745  *      visible from the caller point of view.
746  */
747 gboolean
748 mono_security_core_clr_ensure_delegate_creation (MonoMethod *method, MonoError *error)
749 {
750         MonoMethod *caller;
751
752         error_init (error);
753
754         /* note: mscorlib creates delegates to avoid reflection (optimization), we ignore those cases */
755         if (can_avoid_corlib_reflection_delegate_optimization (method))
756                 return TRUE;
757
758         caller = get_reflection_caller ();
759         /* if the "real" caller is not Transparent then it do can anything */
760         if (mono_security_core_clr_method_level (caller, TRUE) != MONO_SECURITY_CORE_CLR_TRANSPARENT)
761                 return TRUE;
762
763         /* otherwise it (as a Transparent caller) cannot create a delegate on a Critical method... */
764         if (mono_security_core_clr_method_level (method, TRUE) == MONO_SECURITY_CORE_CLR_CRITICAL) {
765                 mono_error_set_exception_instance (error, get_argument_exception (
766                         "Transparent method %s cannot create a delegate on Critical method %s.", 
767                         caller, method));
768                 return FALSE;
769         }
770
771         if (mono_security_core_clr_get_options () & MONO_SECURITY_CORE_CLR_OPTIONS_RELAX_DELEGATE) {
772                 if (!mono_security_core_clr_is_platform_image (method->klass->image))
773                         return TRUE;
774         }
775
776         /* also it cannot create the delegate on a method that is not visible from it's (caller) point of view */
777         if (!check_method_access (caller, method)) {
778                 mono_error_set_exception_instance (error, get_method_access_exception (
779                         "Transparent method %s cannot create a delegate on private/internal method %s.", 
780                         caller, method));
781                 return FALSE;
782         }
783
784         return TRUE;
785 }
786
787 /*
788  * mono_security_core_clr_ensure_dynamic_method_resolved_object:
789  *
790  *      Called from mono_reflection_create_dynamic_method (reflection.c) to add some extra checks required for CoreCLR.
791  *      Dynamic methods needs to check to see if the objects being used (e.g. methods, fields) comes from platform code
792  *      and do an accessibility check in this case. Otherwise (i.e. user/application code) can be used without this extra
793  *      accessbility check.
794  */
795 MonoException*
796 mono_security_core_clr_ensure_dynamic_method_resolved_object (gpointer ref, MonoClass *handle_class)
797 {
798         /* XXX find/create test cases for other handle_class XXX */
799         if (handle_class == mono_defaults.fieldhandle_class) {
800                 MonoClassField *field = (MonoClassField*) ref;
801                 MonoClass *klass = mono_field_get_parent (field);
802                 /* fields coming from platform code have extra protection (accessibility check) */
803                 if (mono_security_core_clr_is_platform_image (klass->image)) {
804                         MonoMethod *caller = get_reflection_caller ();
805                         /* XXX Critical code probably can do this / need some test cases (safer off otherwise) XXX */
806                         if (!check_field_access (caller, field)) {
807                                 return get_field_access_exception (
808                                         "Dynamic method %s cannot create access private/internal field %s.", 
809                                         caller, field);
810                         }
811                 }
812         } else if (handle_class == mono_defaults.methodhandle_class) {
813                 MonoMethod *method = (MonoMethod*) ref;
814                 /* methods coming from platform code have extra protection (accessibility check) */
815                 if (mono_security_core_clr_is_platform_image (method->klass->image)) {
816                         MonoMethod *caller = get_reflection_caller ();
817                         /* XXX Critical code probably can do this / need some test cases (safer off otherwise) XXX */
818                         if (!check_method_access (caller, method)) {
819                                 return get_method_access_exception (
820                                         "Dynamic method %s cannot create access private/internal method %s.", 
821                                         caller, method);
822                         }
823                 }
824         }
825         return NULL;
826 }
827
828 /*
829  * mono_security_core_clr_can_access_internals
830  *
831  *      Check if we allow [InternalsVisibleTo] to work between two images.
832  */
833 gboolean
834 mono_security_core_clr_can_access_internals (MonoImage *accessing, MonoImage* accessed)
835 {
836         /* are we trying to access internals of a platform assembly ? if not this is acceptable */
837         if (!mono_security_core_clr_is_platform_image (accessed))
838                 return TRUE;
839
840         /* we can't let everyone with the right name and public key token access the internals of platform code.
841          * (Silverlight can rely on the strongname signature of the assemblies, but Mono does not verify them)
842          * However platform code is fully trusted so it can access the internals of other platform code assemblies */
843         if (mono_security_core_clr_is_platform_image (accessing))
844                 return TRUE;
845
846         /* catch-22: System.Xml needs access to mscorlib's internals (e.g. ArrayList) but is not considered platform code.
847          * Promoting it to platform code would create another issue since (both Mono/Moonlight or MS version of) 
848          * System.Xml.Linq.dll (an SDK, not platform, assembly) needs access to System.Xml.dll internals (either ). 
849          * The solution is to trust, even transparent code, in the plugin directory to access platform code internals */
850         if (!accessed->assembly->basedir || !accessing->assembly->basedir)
851                 return FALSE;
852         return (strcmp (accessed->assembly->basedir, accessing->assembly->basedir) == 0);
853 }
854
855 /*
856  * mono_security_core_clr_is_field_access_allowed
857  *
858  *      Return a MonoException (FieldccessException in managed-land) if
859  *      the access from "caller" to "field" is not valid under CoreCLR -
860  *      i.e. a [SecurityTransparent] method calling a [SecurityCritical]
861  *      field.
862  */
863 MonoException*
864 mono_security_core_clr_is_field_access_allowed (MonoMethod *caller, MonoClassField *field)
865 {
866         /* there's no restriction to access Transparent or SafeCritical fields, so we only check calls to Critical methods */
867         if (mono_security_core_clr_class_level (mono_field_get_parent (field)) != MONO_SECURITY_CORE_CLR_CRITICAL)
868                 return NULL;
869
870         /* caller is Critical! only SafeCritical and Critical callers can access the field, so we throw if caller is Transparent */
871         if (!caller || (mono_security_core_clr_method_level (caller, TRUE) != MONO_SECURITY_CORE_CLR_TRANSPARENT))
872                 return NULL;
873
874         return get_field_access_exception (
875                 "Transparent method %s cannot call use Critical field %s.", 
876                 caller, field);
877 }
878
879 /*
880  * mono_security_core_clr_is_call_allowed
881  *
882  *      Return a MonoException (MethodAccessException in managed-land) if
883  *      the call from "caller" to "callee" is not valid under CoreCLR -
884  *      i.e. a [SecurityTransparent] method calling a [SecurityCritical]
885  *      method.
886  */
887 MonoException*
888 mono_security_core_clr_is_call_allowed (MonoMethod *caller, MonoMethod *callee)
889 {
890         /* there's no restriction to call Transparent or SafeCritical code, so we only check calls to Critical methods */
891         if (mono_security_core_clr_method_level (callee, TRUE) != MONO_SECURITY_CORE_CLR_CRITICAL)
892                 return NULL;
893
894         /* callee is Critical! only SafeCritical and Critical callers can call it, so we throw if the caller is Transparent */
895         if (!caller || (mono_security_core_clr_method_level (caller, TRUE) != MONO_SECURITY_CORE_CLR_TRANSPARENT))
896                 return NULL;
897
898         return get_method_access_exception (
899                 "Transparent method %s cannot call Critical method %s.", 
900                 caller, callee);
901 }
902
903 /*
904  * mono_security_core_clr_level_from_cinfo:
905  *
906  *      Return the MonoSecurityCoreCLRLevel that match the attribute located
907  *      in the specified custom attributes. If no attribute is present it 
908  *      defaults to MONO_SECURITY_CORE_CLR_TRANSPARENT, which is the default
909  *      level for all code under the CoreCLR.
910  */
911 static MonoSecurityCoreCLRLevel
912 mono_security_core_clr_level_from_cinfo (MonoCustomAttrInfo *cinfo, MonoImage *image)
913 {
914         int level = MONO_SECURITY_CORE_CLR_TRANSPARENT;
915
916         if (cinfo && mono_custom_attrs_has_attr (cinfo, security_safe_critical_attribute ()))
917                 level = MONO_SECURITY_CORE_CLR_SAFE_CRITICAL;
918         if (cinfo && mono_custom_attrs_has_attr (cinfo, security_critical_attribute ()))
919                 level = MONO_SECURITY_CORE_CLR_CRITICAL;
920
921         return (MonoSecurityCoreCLRLevel)level;
922 }
923
924 /*
925  * mono_security_core_clr_class_level_no_platform_check:
926  *
927  *      Return the MonoSecurityCoreCLRLevel for the specified class, without 
928  *      checking for platform code. This help us avoid multiple redundant 
929  *      checks, e.g.
930  *      - a check for the method and one for the class;
931  *      - a check for the class and outer class(es) ...
932  */
933 static MonoSecurityCoreCLRLevel
934 mono_security_core_clr_class_level_no_platform_check (MonoClass *klass)
935 {
936         MonoSecurityCoreCLRLevel level = MONO_SECURITY_CORE_CLR_TRANSPARENT;
937         MonoCustomAttrInfo *cinfo = mono_custom_attrs_from_class (klass);
938         if (cinfo) {
939                 level = mono_security_core_clr_level_from_cinfo (cinfo, klass->image);
940                 mono_custom_attrs_free (cinfo);
941         }
942
943         if (level == MONO_SECURITY_CORE_CLR_TRANSPARENT && klass->nested_in)
944                 level = mono_security_core_clr_class_level_no_platform_check (klass->nested_in);
945
946         return level;
947 }
948
949 /*
950  * mono_security_core_clr_class_level:
951  *
952  *      Return the MonoSecurityCoreCLRLevel for the specified class.
953  */
954 MonoSecurityCoreCLRLevel
955 mono_security_core_clr_class_level (MonoClass *klass)
956 {
957         /* non-platform code is always Transparent - whatever the attributes says */
958         if (!mono_security_core_clr_test && !mono_security_core_clr_is_platform_image (klass->image))
959                 return MONO_SECURITY_CORE_CLR_TRANSPARENT;
960
961         return mono_security_core_clr_class_level_no_platform_check (klass);
962 }
963
964 /*
965  * mono_security_core_clr_field_level:
966  *
967  *      Return the MonoSecurityCoreCLRLevel for the specified field.
968  *      If with_class_level is TRUE then the type (class) will also be
969  *      checked, otherwise this will only report the information about
970  *      the field itself.
971  */
972 MonoSecurityCoreCLRLevel
973 mono_security_core_clr_field_level (MonoClassField *field, gboolean with_class_level)
974 {
975         MonoCustomAttrInfo *cinfo;
976         MonoSecurityCoreCLRLevel level = MONO_SECURITY_CORE_CLR_TRANSPARENT;
977
978         /* if get_reflection_caller returns NULL then we assume the caller has NO privilege */
979         if (!field)
980                 return level;
981
982         /* non-platform code is always Transparent - whatever the attributes says */
983         if (!mono_security_core_clr_test && !mono_security_core_clr_is_platform_image (field->parent->image))
984                 return level;
985
986         cinfo = mono_custom_attrs_from_field (field->parent, field);
987         if (cinfo) {
988                 level = mono_security_core_clr_level_from_cinfo (cinfo, field->parent->image);
989                 mono_custom_attrs_free (cinfo);
990         }
991
992         if (with_class_level && level == MONO_SECURITY_CORE_CLR_TRANSPARENT)
993                 level = mono_security_core_clr_class_level (field->parent);
994
995         return level;
996 }
997
998 /*
999  * mono_security_core_clr_method_level:
1000  *
1001  *      Return the MonoSecurityCoreCLRLevel for the specified method.
1002  *      If with_class_level is TRUE then the type (class) will also be
1003  *      checked, otherwise this will only report the information about
1004  *      the method itself.
1005  */
1006 MonoSecurityCoreCLRLevel
1007 mono_security_core_clr_method_level (MonoMethod *method, gboolean with_class_level)
1008 {
1009         MonoCustomAttrInfo *cinfo;
1010         MonoSecurityCoreCLRLevel level = MONO_SECURITY_CORE_CLR_TRANSPARENT;
1011
1012         /* if get_reflection_caller returns NULL then we assume the caller has NO privilege */
1013         if (!method)
1014                 return level;
1015
1016         /* non-platform code is always Transparent - whatever the attributes says */
1017         if (!mono_security_core_clr_test && !mono_security_core_clr_is_platform_image (method->klass->image))
1018                 return level;
1019
1020         cinfo = mono_custom_attrs_from_method (method);
1021         if (cinfo) {
1022                 level = mono_security_core_clr_level_from_cinfo (cinfo, method->klass->image);
1023                 mono_custom_attrs_free (cinfo);
1024         }
1025
1026         if (with_class_level && level == MONO_SECURITY_CORE_CLR_TRANSPARENT)
1027                 level = mono_security_core_clr_class_level (method->klass);
1028
1029         return level;
1030 }
1031
1032 /*
1033  * mono_security_enable_core_clr:
1034  *
1035  *   Enable the verifier and the CoreCLR security model
1036  */
1037 void
1038 mono_security_enable_core_clr ()
1039 {
1040         mono_verifier_set_mode (MONO_VERIFIER_MODE_VERIFIABLE);
1041         mono_security_set_mode (MONO_SECURITY_MODE_CORE_CLR);
1042 }
1043
1044 #else
1045
1046 void
1047 mono_security_core_clr_check_inheritance (MonoClass *klass)
1048 {
1049 }
1050
1051 void
1052 mono_security_core_clr_check_override (MonoClass *klass, MonoMethod *override, MonoMethod *base)
1053 {
1054 }
1055
1056 gboolean
1057 mono_security_core_clr_require_elevated_permissions (void)
1058 {
1059         return FALSE;
1060 }
1061
1062 gboolean
1063 mono_security_core_clr_ensure_reflection_access_field (MonoClassField *field, MonoError *error)
1064 {
1065         error_init (error);
1066         return TRUE;
1067 }
1068
1069 gboolean
1070 mono_security_core_clr_ensure_reflection_access_method (MonoMethod *method, MonoError *error)
1071 {
1072         error_init (error);
1073         return TRUE;
1074 }
1075
1076 gboolean
1077 mono_security_core_clr_ensure_delegate_creation (MonoMethod *method, MonoError *error)
1078 {
1079         error_init (error);
1080         return TRUE;
1081 }
1082
1083 MonoException*
1084 mono_security_core_clr_ensure_dynamic_method_resolved_object (gpointer ref, MonoClass *handle_class)
1085 {
1086         return NULL;
1087 }
1088
1089 gboolean
1090 mono_security_core_clr_can_access_internals (MonoImage *accessing, MonoImage* accessed)
1091 {
1092         return TRUE;
1093 }
1094
1095 MonoException*
1096 mono_security_core_clr_is_field_access_allowed (MonoMethod *caller, MonoClassField *field)
1097 {
1098         return NULL;
1099 }
1100
1101 MonoException*
1102 mono_security_core_clr_is_call_allowed (MonoMethod *caller, MonoMethod *callee)
1103 {
1104         return NULL;
1105 }
1106
1107 MonoSecurityCoreCLRLevel
1108 mono_security_core_clr_class_level (MonoClass *klass)
1109 {
1110         return MONO_SECURITY_CORE_CLR_TRANSPARENT;
1111 }
1112
1113 MonoSecurityCoreCLRLevel
1114 mono_security_core_clr_field_level (MonoClassField *field, gboolean with_class_level)
1115 {
1116         return MONO_SECURITY_CORE_CLR_TRANSPARENT;
1117 }
1118
1119 MonoSecurityCoreCLRLevel
1120 mono_security_core_clr_method_level (MonoMethod *method, gboolean with_class_level)
1121 {
1122         return MONO_SECURITY_CORE_CLR_TRANSPARENT;
1123 }
1124
1125 void
1126 mono_security_enable_core_clr ()
1127 {
1128 }
1129
1130 #endif /* DISABLE_SECURITY */