Moved ProviderCollectionTest.cs from System assembly to System.Configuration.
[mono.git] / mono / mini / declsec.c
index 3ee9660c052e0669960eee17c59266c3574e3352..65e38d7f8fe5b29cb3e0b517954faace3cd71875 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include "declsec.h"
+#include "mini.h"
 
 /*
  * Does the methods (or it's class) as any declarative security attribute ?
@@ -16,7 +17,9 @@
 MonoBoolean
 mono_method_has_declsec (MonoMethod *method)
 {
-       if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
+       mono_jit_stats.cas_declsec_check++;
+
+       if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE || method->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED) {
                method = mono_marshal_method_from_wrapper (method);
                if (!method)
                        return FALSE;
@@ -67,7 +70,8 @@ mono_declsec_create_frame (MonoDomain *domain, MonoJitInfo *jinfo)
                jinfo->cas_inited = TRUE;
        }
 
-       frame->method = mono_method_get_object (domain, jinfo->method, NULL);
+       MONO_OBJECT_SETREF (frame, method, mono_method_get_object (domain, jinfo->method, NULL));
+       MONO_OBJECT_SETREF (frame, domain, domain->domain);
 
        /* stack modifiers on methods have priority on (i.e. replaces) modifiers on class */
 
@@ -112,6 +116,8 @@ mono_declsec_linkdemand_standard (MonoDomain *domain, MonoMethod *caller, MonoMe
 {
        MonoDeclSecurityActions linkclass, linkmethod;
 
+       mono_jit_stats.cas_linkdemand++;
+
        if (mono_declsec_get_linkdemands (callee, &linkclass, &linkmethod)) {
                MonoAssembly *assembly = mono_image_get_assembly (caller->klass->image);
                MonoReflectionAssembly *refass = (MonoReflectionAssembly*) mono_assembly_get_object (domain, assembly);
@@ -129,13 +135,47 @@ mono_declsec_linkdemand_standard (MonoDomain *domain, MonoMethod *caller, MonoMe
        return FALSE;
 }
 
+/*
+ * Ensure that the restrictions for partially trusted code are satisfied.
+ *
+ * @domain     The current application domain
+ * @assembly   The assembly to query
+ * return value: TRUE if the assembly is runnning at FullTrust, FALSE otherwise.
+ */
+static gboolean
+mono_declsec_is_assembly_fulltrust (MonoDomain *domain, MonoAssembly *assembly)
+{
+       if (!MONO_SECMAN_FLAG_INIT (assembly->fulltrust)) {
+               MonoReflectionAssembly *refass = (MonoReflectionAssembly*) mono_assembly_get_object (domain, assembly);
+               MonoSecurityManager *secman = mono_security_manager_get_methods ();
+
+               if (secman && refass) {
+                       MonoObject *res;
+                       gpointer args [1];
+                       args [0] = refass;
+
+                       res = mono_runtime_invoke (secman->linkdemandfulltrust, NULL, args, NULL);
+                       if (*(MonoBoolean *) mono_object_unbox(res)) {
+                               /* keep this value cached as it will be used very often */
+                               MONO_SECMAN_FLAG_SET_VALUE (assembly->fulltrust, TRUE);
+                               return TRUE;
+                       }
+               }
+
+               MONO_SECMAN_FLAG_SET_VALUE (assembly->fulltrust, FALSE);
+               return FALSE;
+       }
+
+       return MONO_SECMAN_FLAG_GET_VALUE (assembly->fulltrust);
+}
+
 /*
  * Ensure that the restrictions for partially trusted code are satisfied.
  *
  * @domain     The current application domain
  * @caller     The method calling
  * @callee     The called method
- * return value: TRUE if a security violation is detection, FALSE otherwise.
+ * return value: TRUE if a security violation is detected, FALSE otherwise.
  *
  * If callee's assembly is strongnamed and doesn't have an 
  * [AllowPartiallyTrustedCallers] attribute then we must enforce a LinkDemand
@@ -146,10 +186,12 @@ mono_declsec_linkdemand_standard (MonoDomain *domain, MonoMethod *caller, MonoMe
 static gboolean
 mono_declsec_linkdemand_aptc (MonoDomain *domain, MonoMethod *caller, MonoMethod *callee)
 {
-       MonoSecurityManager* secman;
+       MonoSecurityManager* secman = NULL;
        MonoAssembly *assembly;
        guint32 size = 0;
 
+       mono_jit_stats.cas_linkdemand_aptc++;
+
        /* A - Applicable only if we're calling into *another* assembly */
        if (caller->klass->image == callee->klass->image)
                return FALSE;
@@ -166,12 +208,14 @@ mono_declsec_linkdemand_aptc (MonoDomain *domain, MonoMethod *caller, MonoMethod
        assembly = mono_image_get_assembly (callee->klass->image);
        if (!MONO_SECMAN_FLAG_INIT (assembly->aptc)) {
                MonoCustomAttrInfo* cinfo = mono_custom_attrs_from_assembly (assembly);
-               secman = mono_security_manager_get_methods ();
                gboolean result = FALSE;
+               secman = mono_security_manager_get_methods ();
                if (secman && cinfo) {
                        /* look for AllowPartiallyTrustedCallersAttribute */
-                       result = mono_custom_attrs_has_attr (cinfo, secman->aptc);
+                       result = mono_custom_attrs_has_attr (cinfo, secman->allowpartiallytrustedcallers);
                }
+               if (cinfo)
+                       mono_custom_attrs_free (cinfo);
                MONO_SECMAN_FLAG_SET_VALUE (assembly->aptc, result);
        }
 
@@ -179,28 +223,8 @@ mono_declsec_linkdemand_aptc (MonoDomain *domain, MonoMethod *caller, MonoMethod
                return FALSE;
 
        /* E - the caller's assembly must have full trust permissions */
-       if (!MONO_SECMAN_FLAG_INIT (assembly->fulltrust)) {
-               MonoReflectionAssembly *refass = (MonoReflectionAssembly*) mono_assembly_get_object (domain, assembly);
-               if (!secman)
-                       secman = mono_security_manager_get_methods ();
-
-               if (secman && refass) {
-                       MonoObject *res;
-                       gpointer args [1];
-                       args [0] = refass;
-
-                       res = mono_runtime_invoke (secman->linkdemandfulltrust, NULL, args, NULL);
-                       if (*(MonoBoolean *) mono_object_unbox(res)) {
-                               /* keep this value cached as it will be used very often */
-                               MONO_SECMAN_FLAG_SET_VALUE (assembly->fulltrust, TRUE);
-                               return FALSE;
-                       }
-               }
-
-               MONO_SECMAN_FLAG_SET_VALUE (assembly->fulltrust, FALSE);
-       }
-
-       if (MONO_SECMAN_FLAG_GET_VALUE (assembly->fulltrust))
+       assembly = mono_image_get_assembly (caller->klass->image);
+       if (mono_declsec_is_assembly_fulltrust (domain, assembly))
                return FALSE;
 
        /* g_warning ("FAILURE *** JIT LinkDemand APTC check *** %s.%s calls into %s.%s",
@@ -209,54 +233,13 @@ mono_declsec_linkdemand_aptc (MonoDomain *domain, MonoMethod *caller, MonoMethod
        return TRUE;    /* i.e. throw new SecurityException(); */
 }
 
-/*
- * Ensure that the restrictions for calling internal calls are satisfied.
- *
- * @caller     The method calling
- * @icall      The internal call method
- * return value: TRUE if a security violation is detection, FALSE otherwise.
- *
- * Executing internal calls (icalls) is a restricted operation. Only 
- * assemblies with an ECMA public key are allowed to call them (unless they
- * are publicly available).
- *
- * This LinkDemand case is special because it can be done without calling 
- * managed code.
- */
-static gboolean
-mono_declsec_linkdemand_ecma (MonoMethod *caller, MonoMethod *icall)
-{
-       MonoAssembly *assembly;
-
-       /* some icall are public (i.e. they CAN be called by any code) */
-       if (((icall->klass->flags & TYPE_ATTRIBUTE_PUBLIC) == TYPE_ATTRIBUTE_PUBLIC) &&
-               ((icall->flags & FIELD_ATTRIBUTE_PUBLIC) == FIELD_ATTRIBUTE_PUBLIC)) {
-               return FALSE;
-       }
-
-       assembly = mono_image_get_assembly (icall->klass->image);
-       if (!MONO_SECMAN_FLAG_INIT (assembly->ecma)) {
-               guint32 size = 0;
-               const char *pk = mono_image_get_public_key (caller->klass->image, &size);
-               MONO_SECMAN_FLAG_SET_VALUE (assembly->ecma, mono_is_ecma_key (pk, size));
-       }
-
-       if (MONO_SECMAN_FLAG_GET_VALUE (assembly->ecma))
-               return FALSE;
-
-       /* g_warning ("FAILURE *** JIT LinkDemand for ECMA check *** %s.%s calls into %s.%s", 
-               caller->klass->name, caller->name, icall->klass->name, icall->name); */
-
-       return TRUE;    /* i.e. throw new SecurityException(); */
-}
-
 /*
  * Ensure that the restrictions for calling native code are satisfied.
  *
  * @domain     The current application domain
  * @caller     The method calling
  * @native     The native method called
- * return value: TRUE if a security violation is detection, FALSE otherwise.
+ * return value: TRUE if a security violation is detected, FALSE otherwise.
  *
  * Executing Platform Invokes (P/Invoke) is a is a restricted operation.
  * The security policy must allow (SecurityPermissionFlag.UnmanagedCode)
@@ -279,12 +262,15 @@ mono_declsec_linkdemand_pinvoke (MonoDomain *domain, MonoMethod *caller, MonoMet
 {
        MonoAssembly *assembly = mono_image_get_assembly (caller->klass->image);
 
+       mono_jit_stats.cas_linkdemand_pinvoke++;
+
        /* Check for P/Invoke flag for the assembly */
        if (!MONO_SECMAN_FLAG_INIT (assembly->unmanaged)) {
                /* Check if we know (and have) or FullTrust status */
                if (MONO_SECMAN_FLAG_INIT (assembly->fulltrust) && MONO_SECMAN_FLAG_GET_VALUE (assembly->fulltrust)) {
                        /* FullTrust includes UnmanagedCode permission */
                        MONO_SECMAN_FLAG_SET_VALUE (assembly->unmanaged, TRUE);
+                       return FALSE;
                } else {
                        MonoReflectionAssembly *refass = (MonoReflectionAssembly*) mono_assembly_get_object (domain, assembly);
                        MonoSecurityManager* secman = mono_security_manager_get_methods ();
@@ -313,6 +299,46 @@ mono_declsec_linkdemand_pinvoke (MonoDomain *domain, MonoMethod *caller, MonoMet
        return TRUE;    /* i.e. throw new SecurityException(); */
 }
 
+/*
+ * Ensure that the restrictions for calling internal calls are satisfied.
+ *
+ * @domain     The current application domain
+ * @caller     The method calling
+ * @icall      The internal call method
+ * return value: TRUE if a security violation is detected, FALSE otherwise.
+ *
+ * We can't trust the icall flags/iflags as it comes from the assembly
+ * that we may want to restrict and we do not have the public/restricted
+ * information about icalls in the runtime. Actually it is not so bad 
+ * as the CLR 2.0 doesn't enforce that restriction anymore.
+ * 
+ * So we'll limit the icalls to originate from ECMA signed assemblies 
+ * (as this is required for partial trust scenarios) - or - assemblies that 
+ * have FullTrust.
+ */
+static gboolean
+mono_declsec_linkdemand_icall (MonoDomain *domain, MonoMethod *caller, MonoMethod *icall)
+{
+       MonoAssembly *assembly;
+
+       mono_jit_stats.cas_linkdemand_icall++;
+
+       /* check if the _icall_ is defined inside an ECMA signed assembly */
+       assembly = mono_image_get_assembly (icall->klass->image);
+       if (!MONO_SECMAN_FLAG_INIT (assembly->ecma)) {
+               guint32 size = 0;
+               const char *pk = mono_image_get_public_key (icall->klass->image, &size);
+               MONO_SECMAN_FLAG_SET_VALUE (assembly->ecma, mono_is_ecma_key (pk, size));
+       }
+
+       if (MONO_SECMAN_FLAG_GET_VALUE (assembly->ecma))
+               return FALSE;
+
+       /* else check if the _calling_ assembly is running at FullTrust */
+       assembly = mono_image_get_assembly (caller->klass->image);
+       return !mono_declsec_is_assembly_fulltrust (domain, assembly);
+}
+
 
 /*
  * Before the JIT can link (call) into a method the following security checks
@@ -335,11 +361,17 @@ guint32
 mono_declsec_linkdemand (MonoDomain *domain, MonoMethod *caller, MonoMethod *callee)
 {
        guint32 violation = MONO_JIT_SECURITY_OK;
-       /* first, the special (implied) linkdemand */
+
+       /* short-circuit corlib as it is fully trusted (within itself)
+        * and because this cause major recursion headaches */
+       if ((caller->klass->image == mono_defaults.corlib) && (callee->klass->image == mono_defaults.corlib))
+               return violation;
+
+       /* next, the special (implied) linkdemand */
 
        if (callee->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
-               /* restrict calls into the runtime to ECMA signed assemblies */
-               if (mono_declsec_linkdemand_ecma (caller, callee))
+               /* restrict internal calls into the runtime */
+               if (mono_declsec_linkdemand_icall (domain, caller, callee))
                        violation = MONO_JIT_LINKDEMAND_ECMA;
        } else if (callee->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
                /* CAS can restrict p/invoke calls with the assembly granted permissions */