Hello,

Here's the first of the coreclr mini-patches. It work (commit-ready)
independently of the other changes.

It's near identical to the previous patch: one function was renamed (as
requested) and some comments were updated. The needed
SecurityManager.FieldAccessException method is already in SVN.

Thanks
Sebastien
Index: mono/mini/method-to-ir.c
===================================================================
--- mono/mini/method-to-ir.c	(revision 129771)
+++ mono/mini/method-to-ir.c	(working copy)
@@ -4459,21 +4459,83 @@
 	mono_emit_method_call (cfg, thrower, args, NULL);
 }
 
+static MonoMethod*
+field_access_exception (void)
+{
+	static MonoMethod *method = NULL;
+
+	if (!method) {
+		MonoSecurityManager *secman = mono_security_manager_get_methods ();
+		method = mono_class_get_method_from_name (secman->securitymanager,
+							  "FieldAccessException", 2);
+	}
+	g_assert (method);
+	return method;
+}
+
 static void
+emit_throw_field_access_exception (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field,
+				    MonoBasicBlock *bblock, unsigned char *ip)
+{
+	MonoMethod *thrower = field_access_exception ();
+	MonoInst *args [2];
+
+	EMIT_NEW_METHODCONST (cfg, args [0], caller);
+	EMIT_NEW_METHODCONST (cfg, args [1], field);
+	mono_emit_method_call (cfg, thrower, args, NULL);
+}
+
+/*
+ * Return the original method is a wrapper is specified. We can only access 
+ * the custom attributes from the original method.
+ */
+static MonoMethod*
+get_original_method (MonoMethod *method)
+{
+	if (method->wrapper_type == MONO_WRAPPER_NONE)
+		return method;
+
+	/* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
+	if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
+		return NULL;
+
+	/* in other cases we need to find the original method */
+	return mono_marshal_method_from_wrapper (method);
+}
+
+static void
+ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field,
+					  MonoBasicBlock *bblock, unsigned char *ip)
+{
+	/* there's no restriction to access Transparent or SafeCritical fields, so we only check calls to Critical methods */
+	if (mono_security_core_clr_class_level (mono_field_get_parent (field)) != MONO_SECURITY_CORE_CLR_CRITICAL)
+		return;
+
+	/* we can't get the coreclr security level on wrappers since they don't have the attributes */
+	caller = get_original_method (caller);
+	if (!caller)
+		return;
+
+	/* caller is Critical! only SafeCritical and Critical callers can access the field, so we throw if caller is Transparent */
+	if (mono_security_core_clr_method_level (caller, TRUE) == MONO_SECURITY_CORE_CLR_TRANSPARENT)
+		emit_throw_field_access_exception (cfg, caller, field, bblock, ip);
+}
+
+static void
 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
 					 MonoBasicBlock *bblock, unsigned char *ip)
 {
-	MonoSecurityCoreCLRLevel caller_level = mono_security_core_clr_method_level (caller, TRUE);
-	MonoSecurityCoreCLRLevel callee_level = mono_security_core_clr_method_level (callee, TRUE);
-	gboolean is_safe = TRUE;
+	/* there's no restriction to call Transparent or SafeCritical code, so we only check calls to Critical methods */
+	if (mono_security_core_clr_method_level (callee, TRUE) != MONO_SECURITY_CORE_CLR_CRITICAL)
+		return;
 
-	if (!(caller_level >= callee_level ||
-			caller_level == MONO_SECURITY_CORE_CLR_SAFE_CRITICAL ||
-			callee_level == MONO_SECURITY_CORE_CLR_SAFE_CRITICAL)) {
-		is_safe = FALSE;
-	}
+	/* we can't get the coreclr security level on wrappers since they don't have the attributes */
+	caller = get_original_method (caller);
+	if (!caller)
+		return;
 
-	if (!is_safe)
+	/* caller is Critical! only SafeCritical and Critical callers can call it, so we throw if the caller is Transparent */
+	if (mono_security_core_clr_method_level (caller, TRUE) == MONO_SECURITY_CORE_CLR_TRANSPARENT)
 		emit_throw_method_access_exception (cfg, caller, callee, bblock, ip);
 }
 
@@ -7710,6 +7772,12 @@
 				FIELD_ACCESS_FAILURE;
 			mono_class_init (klass);
 
+			/* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
+			   any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
+			if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+				ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
+			*/
+
 			foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
 			if (*ip == CEE_STFLD) {
 				if (target_type_is_incompatible (cfg, field->type, sp [1]))
@@ -7843,6 +7911,10 @@
 			if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
 				FIELD_ACCESS_FAILURE;
 
+			/* if the class is Critical then transparent code cannot access it's fields */
+			if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+				ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
+
 			/*
 			 * We can only support shared generic static
 			 * field access on architectures where the
Index: mono/mini/ChangeLog
===================================================================
--- mono/mini/ChangeLog	(revision 129771)
+++ mono/mini/ChangeLog	(working copy)
@@ -1,3 +1,9 @@
+2009-03-19  Sebastien Pouliot  <[email protected]>
+
+	* method-to-ir.c: Allow CoreCLR to throw FieldAccessException. 
+	Simplify logic for ensure_method_is_allowed_to_call_method. 
+	Handle wrappers on callers.
+
 2009-03-18  Geoff Norton  <[email protected]>
 
 	* mini.c: Only chain sigfpe if it wasn't generated in mangaed code.
_______________________________________________
Mono-devel-list mailing list
[email protected]
http://lists.ximian.com/mailman/listinfo/mono-devel-list

Reply via email to