Commit message: Disable some of the FastCopy fast paths since they are racy.
CVE: CVE-2011-0989
CWE: CWE-264
Vulnerability description: The RuntimeHelpers.InitializeArray method in metadata/icall.c in Mono, when Moonlight 2.x before 2.4.1 or 3.x before 3.99.3 is used, does not properly restrict data types, which allows remote attackers to modify internal read-only data structures, and cause a denial of service (plugin crash) or corrupt the internal state of the security manager, via a crafted media file, as demonstrated by modifying a C# struct.

Project: mono
File: icall.c

find_class_icalls (const char *name)
{
	const char **nameslot = bsearch (name, icall_type_names, Icall_type_num, sizeof (icall_type_names [0]), compare_class_imap);
	if (!nameslot)
		return NULL;
	return &icall_type_descs [nameslot - icall_type_names];
}

Project: mono
File: icall.c

ves_icall_System_Reflection_Assembly_FillName (MonoReflectionAssembly *assembly, MonoReflectionAssemblyName *aname)
{
	gchar *absolute;
	MonoAssembly *mass = assembly->assembly;

	MONO_ARCH_SAVE_REGS;

	if (g_path_is_absolute (mass->image->name)) {
		fill_reflection_assembly_name (mono_object_domain (assembly),
			aname, &mass->aname, mass->image->name, TRUE,
			TRUE, mono_framework_version () >= 2);
		return;
	}
	absolute = g_build_filename (mass->basedir, mass->image->name, NULL);

	fill_reflection_assembly_name (mono_object_domain (assembly),
		aname, &mass->aname, absolute, TRUE, TRUE,
		mono_framework_version () >= 2);

	g_free (absolute);
}

Project: mono
File: icall.c

ves_icall_System_Enum_get_value (MonoObject *this)
{
	MonoObject *res;
	MonoClass *enumc;
	gpointer dst;
	gpointer src;
	int size;

	MONO_ARCH_SAVE_REGS;

	if (!this)
		return NULL;

	g_assert (this->vtable->klass->enumtype);
	
	enumc = mono_class_from_mono_type (mono_class_enum_basetype (this->vtable->klass));
	res = mono_object_new (mono_object_domain (this), enumc);
	dst = (char *)res + sizeof (MonoObject);
	src = (char *)this + sizeof (MonoObject);
	size = mono_class_value_size (enumc, NULL);

	memcpy (dst, src, size);

	return res;
}

Project: mono
File: icall.c

ves_icall_System_Array_GetValueImpl (MonoObject *this, guint32 pos)
{
	MonoClass *ac;
	MonoArray *ao;
	gint32 esize;
	gpointer *ea;

	MONO_ARCH_SAVE_REGS;

	ao = (MonoArray *)this;
	ac = (MonoClass *)ao->obj.vtable->klass;

	esize = mono_array_element_size (ac);
	ea = (gpointer*)((char*)ao->vector + (pos * esize));

	if (ac->element_class->valuetype)
		return mono_value_box (this->vtable->domain, ac->element_class, ea);
	else
		return *ea;
}

Project: mono
File: icall.c

ves_icall_System_Reflection_MethodBase_GetMethodFromHandleInternalType (MonoMethod *method, MonoType *type)
{
	MonoClass *klass;
	if (type) {
		klass = mono_class_from_mono_type (type);
		if (mono_class_get_generic_type_definition (method->klass) != mono_class_get_generic_type_definition (klass)) 
			return NULL;
		if (method->klass != klass) {
			method = mono_method_get_equivalent_method (method, klass);
			if (!method)
				return NULL;
		}
	} else
		klass = method->klass;
	return mono_method_get_object (mono_domain_get (), method, klass);
}

Project: mono
File: icall.c

get_caller (MonoMethod *m, gint32 no, gint32 ilo, gboolean managed, gpointer data)
{
	MonoMethod **dest = data;

	/* skip unmanaged frames */
	if (!managed)
		return FALSE;

	if (m == *dest) {
		*dest = NULL;
		return FALSE;
	}
	if (!(*dest)) {
		*dest = m;
		return TRUE;
	}
	return FALSE;
}

Project: mono
File: icall.c

ves_icall_Type_GetInterfaceMapData (MonoReflectionType *type, MonoReflectionType *iface, MonoArray **targets, MonoArray **methods)
{
	MonoClass *class = mono_class_from_mono_type (type->type);
	MonoClass *iclass = mono_class_from_mono_type (iface->type);
	MonoReflectionMethod *member;
	MonoMethod* method;
	gpointer iter;
	int i = 0, len, ioffset;
	MonoDomain *domain;

	MONO_ARCH_SAVE_REGS;

	mono_class_setup_vtable (class);

	/* type doesn't implement iface: the exception is thrown in managed code */
	if (! MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
			return;

	len = mono_class_num_methods (iclass);
	ioffset = mono_class_interface_offset (class, iclass);
	domain = mono_object_domain (type);
	mono_gc_wbarrier_generic_store (targets, (MonoObject*) mono_array_new (domain, mono_defaults.method_info_class, len));
	mono_gc_wbarrier_generic_store (methods, (MonoObject*) mono_array_new (domain, mono_defaults.method_info_class, len));
	iter = NULL;
	while ((method = mono_class_get_methods (iclass, &iter))) {
		member = mono_method_get_object (domain, method, iclass);
		mono_array_setref (*methods, i, member);
		member = mono_method_get_object (domain, class->vtable [i + ioffset], class);
		mono_array_setref (*targets, i, member);
		
		i ++;
	}
}

Project: mono
File: icall.c

ves_icall_System_Reflection_Assembly_InternalImageRuntimeVersion (MonoReflectionAssembly *assembly)
{
	MonoDomain *domain = mono_object_domain (assembly); 

	MONO_ARCH_SAVE_REGS;

	return mono_string_new (domain, assembly->assembly->image->version);
}

Project: mono
File: icall.c

ves_icall_System_Runtime_InteropServices_Marshal_Prelink (MonoReflectionMethod *method)
{
	MONO_ARCH_SAVE_REGS;
	prelink_method (method->method);
}

Project: mono
File: icall.c

compare_method_imap (const void *key, const void *elem)
{
	const char** method_name = (const char**)elem;
	return strcmp (key, *method_name);
}

Project: mono
File: icall.c

ves_icall_type_IsInstanceOfType (MonoReflectionType *type, MonoObject *obj)
{
	MonoClass *klass = mono_class_from_mono_type (type->type);
	return mono_object_isinst (obj, klass) != NULL;
}

Project: mono
File: icall.c

ves_icall_MonoGenericMethod_get_ReflectedType (MonoReflectionGenericMethod *rmethod)
{
	MonoMethod *method = rmethod->method.method;

	return mono_type_get_object (mono_object_domain (rmethod), &method->klass->byval_arg);
}

Project: mono
File: icall.c

ves_icall_System_Reflection_Module_ResolveStringToken (MonoImage *image, guint32 token, MonoResolveTokenError *error)
{
	int index = mono_metadata_token_index (token);

	*error = ResolveTokenError_Other;

	/* Validate token */
	if (mono_metadata_token_code (token) != MONO_TOKEN_STRING) {
		*error = ResolveTokenError_BadTable;
		return NULL;
	}

	if (image->dynamic)
		return mono_lookup_dynamic_token_class (image, token, FALSE, NULL, NULL);

	if ((index <= 0) || (index >= image->heap_us.size)) {
		*error = ResolveTokenError_OutOfRange;
		return NULL;
	}

	/* FIXME: What to do if the index points into the middle of a string ? */

	return mono_ldstr (mono_domain_get (), image, index);
}

Project: mono
File: icall.c

ves_icall_System_IO_DriveInfo_GetDiskFreeSpace (MonoString *path_name, guint64 *free_bytes_avail,
						guint64 *total_number_of_bytes, guint64 *total_number_of_free_bytes,
						gint32 *error)
{
	gboolean result;
	ULARGE_INTEGER wapi_free_bytes_avail;
	ULARGE_INTEGER wapi_total_number_of_bytes;
	ULARGE_INTEGER wapi_total_number_of_free_bytes;

	MONO_ARCH_SAVE_REGS;

	*error = ERROR_SUCCESS;
	result = GetDiskFreeSpaceEx (mono_string_chars (path_name), &wapi_free_bytes_avail, &wapi_total_number_of_bytes,
				     &wapi_total_number_of_free_bytes);

	if (result) {
		*free_bytes_avail = wapi_free_bytes_avail.QuadPart;
		*total_number_of_bytes = wapi_total_number_of_bytes.QuadPart;
		*total_number_of_free_bytes = wapi_total_number_of_free_bytes.QuadPart;
	} else {
		*free_bytes_avail = 0;
		*total_number_of_bytes = 0;
		*total_number_of_free_bytes = 0;
		*error = GetLastError ();
	}

	return result;
}

Project: mono
File: icall.c

ves_icall_System_Reflection_Module_GetHINSTANCE (MonoReflectionModule *module)
{
#ifdef PLATFORM_WIN32
	if (module->image && module->image->is_module_handle)
		return module->image->raw_data;
#endif

	return (gpointer) (-1);
}

Project: mono
File: icall.c

mono_lookup_internal_call (MonoMethod *method)
{
	char *sigstart;
	char *tmpsig;
	char mname [2048];
	int typelen = 0, mlen, siglen;
	gpointer res;
	const IcallTypeDesc *imap;

	g_assert (method != NULL);

	if (method->is_inflated)
		method = ((MonoMethodInflated *) method)->declaring;

	if (method->klass->nested_in) {
		int pos = concat_class_name (mname, sizeof (mname)-2, method->klass->nested_in);
		if (!pos)
			return NULL;

		mname [pos++] = '/';
		mname [pos] = 0;

		typelen = concat_class_name (mname+pos, sizeof (mname)-pos-1, method->klass);
		if (!typelen)
			return NULL;

		typelen += pos;
	} else {
		typelen = concat_class_name (mname, sizeof (mname), method->klass);
		if (!typelen)
			return NULL;
	}

	imap = find_class_icalls (mname);

	mname [typelen] = ':';
	mname [typelen + 1] = ':';

	mlen = strlen (method->name);
	memcpy (mname + typelen + 2, method->name, mlen);
	sigstart = mname + typelen + 2 + mlen;
	*sigstart = 0;

	tmpsig = mono_signature_get_desc (mono_method_signature (method), TRUE);
	siglen = strlen (tmpsig);
	if (typelen + mlen + siglen + 6 > sizeof (mname))
		return NULL;
	sigstart [0] = '(';
	memcpy (sigstart + 1, tmpsig, siglen);
	sigstart [siglen + 1] = ')';
	sigstart [siglen + 2] = 0;
	g_free (tmpsig);
	
	mono_loader_lock ();

	res = g_hash_table_lookup (icall_hash, mname);
	if (res) {
		mono_loader_unlock ();
		return res;
	}
	/* try without signature */
	*sigstart = 0;
	res = g_hash_table_lookup (icall_hash, mname);
	if (res) {
		mono_loader_unlock ();
		return res;
	}

	/* it wasn't found in the static call tables */
	if (!imap) {
		mono_loader_unlock ();
		return NULL;
	}
	res = find_method_icall (imap, sigstart - mlen);
	if (res) {
		mono_loader_unlock ();
		return res;
	}
	/* try _with_ signature */
	*sigstart = '(';
	res = find_method_icall (imap, sigstart - mlen);
	if (res) {
		mono_loader_unlock ();
		return res;
	}

	g_warning ("cant resolve internal call to \"%s\" (tested without signature also)", mname);
	g_print ("\nYour mono runtime and class libraries are out of sync.\n");
	g_print ("The out of sync library is: %s\n", method->klass->image->name);
	g_print ("\nWhen you update one from svn you need to update, compile and install\nthe other too.\n");
	g_print ("Do not report this as a bug unless you're sure you have updated correctly:\nyou probably have a broken mono install.\n");
	g_print ("If you see other errors or faults after this message they are probably related\n");
	g_print ("and you need to fix your mono install first.\n");

	mono_loader_unlock ();

	return NULL;
}

Project: mono
File: icall.c

ves_icall_MonoType_get_IsGenericParameter (MonoReflectionType *type)
{
	MONO_ARCH_SAVE_REGS;
	return is_generic_parameter (type->type);
}

Project: mono
File: icall.c

get_bundled_machine_config (void)
{
	const gchar *machine_config;

	MONO_ARCH_SAVE_REGS;

	machine_config = mono_get_machine_config ();

	if (!machine_config)
		return NULL;

	return mono_string_new (mono_domain_get (), machine_config);
}

Project: mono
File: icall.c

write_enum_value (char *mem, int type, guint64 value)
{
	switch (type) {
	case MONO_TYPE_U1:
	case MONO_TYPE_I1: {
		guint8 *p = (guint8*)mem;
		*p = value;
		break;
	}
	case MONO_TYPE_U2:
	case MONO_TYPE_I2: {
		guint16 *p = (void*)mem;
		*p = value;
		break;
	}
	case MONO_TYPE_U4:
	case MONO_TYPE_I4: {
		guint32 *p = (void*)mem;
		*p = value;
		break;
	}
	case MONO_TYPE_U8:
	case MONO_TYPE_I8: {
		guint64 *p = (void*)mem;
		*p = value;
		break;
	}
	default:
		g_assert_not_reached ();
	}
	return;
}