*/
#include "declsec.h"
+#include "mini.h"
/*
* Does the methods (or it's class) as any declarative security attribute ?
MonoBoolean
mono_method_has_declsec (MonoMethod *method)
{
+ mono_jit_stats.cas_declsec_check++;
+
if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
method = mono_marshal_method_from_wrapper (method);
if (!method)
}
frame->method = mono_method_get_object (domain, jinfo->method, NULL);
+ frame->domain = domain->domain;
/* stack modifiers on methods have priority on (i.e. replaces) modifiers on class */
{
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);
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
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;
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);
}
MONO_SECMAN_FLAG_SET_VALUE (assembly->aptc, result);
}
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",
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)
{
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 ();
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
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 */