Vulnerability: Race condition in the FastCopy optimization in the Array.Copy method in metadata/icall.c in Mono, when Moonlight 2.x before 2.4.1 or 3.x before 3.99.3 is used, allows remote attackers to trigger a buffer overflow and modify internal data structures, and cause a denial of service (plugin crash) or corrupt the internal state of the security manager, via a crafted media file in which a thread makes a change after a type check but before a copy action.
Vulnerability ID: CVE-2011-0990
CWE: CWE-362
Severity score: 4.9
Project: https://github.com/mono/mono
Published: 2011-04-13
File: mono/metadata/icall.c
Commit message: Disable some of the FastCopy fast paths since they are racy.
Commit author: Zoltan Varga

Vulnerable version (before fix):
 ves_icall_System_Array_FastCopy (MonoArray *source, int source_idx, MonoArray* d 	void * source_addr; 	MonoClass *src_class; 	MonoClass *dest_class; 	int i;  	MONO_ARCH_SAVE_REGS;  ves_icall_System_Array_FastCopy (MonoArray *source, int source_idx, MonoArray* d  	/* Case1: object[] -> valuetype[] (ArrayList::ToArray) */ 	if (src_class == mono_defaults.object_class && dest_class->valuetype) { 		int has_refs = dest_class->has_references; 		for (i = source_idx; i < source_idx + length; ++i) { 			MonoObject *elem = mono_array_get (source, MonoObject*, i); ves_icall_System_Array_FastCopy (MonoArray *source, int source_idx, MonoArray* d 				memcpy (addr, (char *)elem + sizeof (MonoObject), element_size); 		} 		return TRUE; 	}  	/* Check if we're copying a char[] <==> (u)short[] */ ves_icall_System_Array_FastCopy (MonoArray *source, int source_idx, MonoArray* d 		if (mono_class_is_subclass_of (src_class, dest_class, FALSE)) 			; 		/* Case2: object[] -> reftype[] (ArrayList::ToArray) */ 		else if (mono_class_is_subclass_of (dest_class, src_class, FALSE)) 			for (i = source_idx; i < source_idx + length; ++i) { 				MonoObject *elem = mono_array_get (source, MonoObject*, i); 				if (elem && !mono_object_isinst (elem, dest_class)) 					return FALSE; 			} 		else 			return FALSE; 	} 

Fixed version (after fix):
 ves_icall_System_Array_FastCopy (MonoArray *source, int source_idx, MonoArray* d 	void * source_addr; 	MonoClass *src_class; 	MonoClass *dest_class;  	MONO_ARCH_SAVE_REGS;  ves_icall_System_Array_FastCopy (MonoArray *source, int source_idx, MonoArray* d  	/* Case1: object[] -> valuetype[] (ArrayList::ToArray) */ 	if (src_class == mono_defaults.object_class && dest_class->valuetype) { 		// FIXME: This is racy 		return FALSE; 		/* 		  int i; 		int has_refs = dest_class->has_references; 		for (i = source_idx; i < source_idx + length; ++i) { 			MonoObject *elem = mono_array_get (source, MonoObject*, i); ves_icall_System_Array_FastCopy (MonoArray *source, int source_idx, MonoArray* d 				memcpy (addr, (char *)elem + sizeof (MonoObject), element_size); 		} 		return TRUE; 		*/ 	}  	/* Check if we're copying a char[] <==> (u)short[] */ ves_icall_System_Array_FastCopy (MonoArray *source, int source_idx, MonoArray* d 		if (mono_class_is_subclass_of (src_class, dest_class, FALSE)) 			; 		/* Case2: object[] -> reftype[] (ArrayList::ToArray) */ 		else if (mono_class_is_subclass_of (dest_class, src_class, FALSE)) { 			// FIXME: This is racy 			return FALSE; 			/* 			  int i; 			for (i = source_idx; i < source_idx + length; ++i) { 				MonoObject *elem = mono_array_get (source, MonoObject*, i); 				if (elem && !mono_object_isinst (elem, dest_class)) 					return FALSE; 			} 			*/ 		} else 			return FALSE; 	} 

Patch:
patch: @@ -718,7 +718,6 @@ ves_icall_System_Array_FastCopy (MonoArray *source, int source_idx, MonoArray* d
 	void * source_addr;
 	MonoClass *src_class;
 	MonoClass *dest_class;
-	int i;
 
 	MONO_ARCH_SAVE_REGS;
 
@@ -742,6 +741,10 @@ ves_icall_System_Array_FastCopy (MonoArray *source, int source_idx, MonoArray* d
 
 	/* Case1: object[] -> valuetype[] (ArrayList::ToArray) */
 	if (src_class == mono_defaults.object_class && dest_class->valuetype) {
+		// FIXME: This is racy
+		return FALSE;
+		/*
+		  int i;
 		int has_refs = dest_class->has_references;
 		for (i = source_idx; i < source_idx + length; ++i) {
 			MonoObject *elem = mono_array_get (source, MonoObject*, i);
@@ -762,6 +765,7 @@ ves_icall_System_Array_FastCopy (MonoArray *source, int source_idx, MonoArray* d
 				memcpy (addr, (char *)elem + sizeof (MonoObject), element_size);
 		}
 		return TRUE;
+		*/
 	}
 
 	/* Check if we're copying a char[] <==> (u)short[] */
@@ -772,13 +776,18 @@ ves_icall_System_Array_FastCopy (MonoArray *source, int source_idx, MonoArray* d
 		if (mono_class_is_subclass_of (src_class, dest_class, FALSE))
 			;
 		/* Case2: object[] -> reftype[] (ArrayList::ToArray) */
-		else if (mono_class_is_subclass_of (dest_class, src_class, FALSE))
+		else if (mono_class_is_subclass_of (dest_class, src_class, FALSE)) {
+			// FIXME: This is racy
+			return FALSE;
+			/*
+			  int i;
 			for (i = source_idx; i < source_idx + length; ++i) {
 				MonoObject *elem = mono_array_get (source, MonoObject*, i);
 				if (elem && !mono_object_isinst (elem, dest_class))
 					return FALSE;
 			}
-		else
+			*/
+		} else
 			return FALSE;
 	}
path: mono/metadata/icall.c