Unrated severityNVD Advisory· Published Apr 13, 2011· Updated Apr 29, 2026
CVE-2011-0991
CVE-2011-0991
Description
Use-after-free vulnerability in Mono, when Moonlight 2.x before 2.4.1 or 3.x before 3.99.3 is used, allows remote attackers to cause a denial of service or possibly have unspecified other impact via vectors related to finalizing and then resurrecting a DynamicMethod instance.
Affected products
7cpe:2.3:a:novell:moonlight:2.0:*:*:*:*:*:*:*+ 5 more
- cpe:2.3:a:novell:moonlight:2.0:*:*:*:*:*:*:*
- cpe:2.3:a:novell:moonlight:2.3.0:*:*:*:*:*:*:*
- cpe:2.3:a:novell:moonlight:2.31:*:*:*:*:*:*:*
- cpe:2.3:a:novell:moonlight:2.4:*:*:*:*:*:*:*
- cpe:2.3:a:novell:moonlight:3.0:*:*:*:*:*:*:*
- cpe:2.3:a:novell:moonlight:3.99:*:*:*:*:*:*:*
Patches
33f8ee42b8c86Don't use finalization to cleanup dynamic methods.
4 files changed · +50 −20
mcs/class/corlib/System.Reflection.Emit/DynamicMethod.cs+0 −8 modified@@ -130,9 +130,6 @@ public DynamicMethod (string name, Type returnType, Type[] parameterTypes, bool [MethodImplAttribute(MethodImplOptions.InternalCall)] private extern void create_dynamic_method (DynamicMethod m); - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private extern void destroy_dynamic_method (DynamicMethod m); - private void CreateDynMethod () { if (mhandle.Value == IntPtr.Zero) { if (ilgen == null || (ILGenerator.Mono_GetCurrentOffset (ilgen) == 0)) @@ -161,11 +158,6 @@ private void CreateDynMethod () { } } - ~DynamicMethod () - { - destroy_dynamic_method (this); - } - [ComVisible (true)] public Delegate CreateDelegate (Type delegateType) {
mono/metadata/icall-def.h+0 −1 modified@@ -513,7 +513,6 @@ ICALL(DERIVEDTYPE_1, "create_unmanaged_type", mono_reflection_create_unmanaged_t ICALL_TYPE(DYNM, "System.Reflection.Emit.DynamicMethod", DYNM_1) ICALL(DYNM_1, "create_dynamic_method", mono_reflection_create_dynamic_method) -ICALL(DYNM_2, "destroy_dynamic_method", mono_reflection_destroy_dynamic_method) ICALL_TYPE(ENUMB, "System.Reflection.Emit.EnumBuilder", ENUMB_1) ICALL(ENUMB_1, "setup_enum_type", ves_icall_EnumBuilder_setup_enum_type)
mono/metadata/object-internals.h+3 −0 modified@@ -1448,6 +1448,9 @@ mono_string_to_utf8_checked (MonoString *s, MonoError *error) MONO_INTERNAL; gboolean mono_class_is_reflection_method_or_constructor (MonoClass *class) MONO_INTERNAL; +void +mono_reflection_shutdown (void) MONO_INTERNAL; + #endif /* __MONO_OBJECT_INTERNALS_H__ */
mono/metadata/reflection.c+47 −11 modified@@ -11064,15 +11064,56 @@ mono_reflection_sighelper_get_signature_field (MonoReflectionSigHelper *sig) return result; } +typedef struct { + MonoMethod *handle; + MonoDomain *domain; +} DynamicMethodReleaseData; + +static MonoReferenceQueue *dynamic_method_queue; + +void +mono_reflection_shutdown (void) +{ + MonoReferenceQueue *queue; + mono_loader_lock (); + queue = dynamic_method_queue; + dynamic_method_queue = NULL; + if (queue) + mono_gc_reference_queue_free (queue); + mono_loader_unlock (); +} + +static void +free_dynamic_method (void *dynamic_method) +{ + DynamicMethodReleaseData *data = dynamic_method; + + mono_runtime_free_method (data->domain, data->handle); + g_free (data); +} + void mono_reflection_create_dynamic_method (MonoReflectionDynamicMethod *mb) { + MonoReferenceQueue *queue; + MonoMethod *handle; + DynamicMethodReleaseData *release_data; ReflectionMethodBuilder rmb; MonoMethodSignature *sig; MonoClass *klass; GSList *l; int i; + if (mono_runtime_is_shutting_down ()) + mono_raise_exception (mono_get_exception_invalid_operation ("")); + + if (!(queue = dynamic_method_queue)) { + mono_loader_lock (); + if (!(queue = dynamic_method_queue)) + queue = dynamic_method_queue = mono_gc_reference_queue_new (free_dynamic_method); + mono_loader_unlock (); + } + sig = dynamic_method_to_signature (mb); reflection_methodbuilder_from_dynamic_method (&rmb, mb); @@ -11130,7 +11171,12 @@ mono_reflection_create_dynamic_method (MonoReflectionDynamicMethod *mb) klass = mb->owner ? mono_class_from_mono_type (mono_reflection_type_get_handle ((MonoReflectionType*)mb->owner)) : mono_defaults.object_class; - mb->mhandle = reflection_methodbuilder_to_mono_method (klass, &rmb, sig); + mb->mhandle = handle = reflection_methodbuilder_to_mono_method (klass, &rmb, sig); + release_data = g_new (DynamicMethodReleaseData, 1); + release_data->handle = handle; + release_data->domain = mono_object_get_domain ((MonoObject*)mb); + if (!mono_gc_reference_queue_add (queue, (MonoObject*)mb, release_data)) + g_free (release_data); /* Fix up refs entries pointing at us */ for (l = mb->referenced_by; l; l = l->next) { @@ -11156,16 +11202,6 @@ mono_reflection_create_dynamic_method (MonoReflectionDynamicMethod *mb) #endif /* DISABLE_REFLECTION_EMIT */ -void -mono_reflection_destroy_dynamic_method (MonoReflectionDynamicMethod *mb) -{ - g_assert (mb); - - if (mb->mhandle) - mono_runtime_free_method ( - mono_object_get_domain ((MonoObject*)mb), mb->mhandle); -} - /** * * mono_reflection_is_valid_dynamic_token:
89d1455a80efDon't use finalization to cleanup dynamic methods.
5 files changed · +53 −20
mcs/class/corlib/System.Reflection.Emit/DynamicMethod.cs+0 −8 modified@@ -127,9 +127,6 @@ public DynamicMethod (string name, Type returnType, Type[] parameterTypes, bool [MethodImplAttribute(MethodImplOptions.InternalCall)] private extern void create_dynamic_method (DynamicMethod m); - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private extern void destroy_dynamic_method (DynamicMethod m); - private void CreateDynMethod () { if (mhandle.Value == IntPtr.Zero) { if (ilgen == null || ilgen.ILOffset == 0) @@ -158,11 +155,6 @@ private void CreateDynMethod () { } } - ~DynamicMethod () - { - destroy_dynamic_method (this); - } - [ComVisible (true)] public Delegate CreateDelegate (Type delegateType) {
mono/metadata/icall-def.h+0 −1 modified@@ -524,7 +524,6 @@ ICALL(DERIVEDTYPE_1, "create_unmanaged_type", mono_reflection_create_unmanaged_t ICALL_TYPE(DYNM, "System.Reflection.Emit.DynamicMethod", DYNM_1) ICALL(DYNM_1, "create_dynamic_method", mono_reflection_create_dynamic_method) -ICALL(DYNM_2, "destroy_dynamic_method", mono_reflection_destroy_dynamic_method) ICALL_TYPE(ENUMB, "System.Reflection.Emit.EnumBuilder", ENUMB_1) ICALL(ENUMB_1, "setup_enum_type", ves_icall_EnumBuilder_setup_enum_type)
mono/metadata/object-internals.h+3 −0 modified@@ -1539,6 +1539,9 @@ mono_object_new_pinned (MonoDomain *domain, MonoClass *klass) MONO_INTERNAL; void mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value) MONO_INTERNAL; +void +mono_reflection_shutdown (void) MONO_INTERNAL; + #endif /* __MONO_OBJECT_INTERNALS_H__ */
mono/metadata/reflection.c+47 −11 modified@@ -11441,15 +11441,56 @@ mono_reflection_sighelper_get_signature_field (MonoReflectionSigHelper *sig) return result; } +typedef struct { + MonoMethod *handle; + MonoDomain *domain; +} DynamicMethodReleaseData; + +static MonoReferenceQueue *dynamic_method_queue; + +void +mono_reflection_shutdown (void) +{ + MonoReferenceQueue *queue; + mono_loader_lock (); + queue = dynamic_method_queue; + dynamic_method_queue = NULL; + if (queue) + mono_gc_reference_queue_free (queue); + mono_loader_unlock (); +} + +static void +free_dynamic_method (void *dynamic_method) +{ + DynamicMethodReleaseData *data = dynamic_method; + + mono_runtime_free_method (data->domain, data->handle); + g_free (data); +} + void mono_reflection_create_dynamic_method (MonoReflectionDynamicMethod *mb) { + MonoReferenceQueue *queue; + MonoMethod *handle; + DynamicMethodReleaseData *release_data; ReflectionMethodBuilder rmb; MonoMethodSignature *sig; MonoClass *klass; GSList *l; int i; + if (mono_runtime_is_shutting_down ()) + mono_raise_exception (mono_get_exception_invalid_operation ("")); + + if (!(queue = dynamic_method_queue)) { + mono_loader_lock (); + if (!(queue = dynamic_method_queue)) + queue = dynamic_method_queue = mono_gc_reference_queue_new (free_dynamic_method); + mono_loader_unlock (); + } + sig = dynamic_method_to_signature (mb); reflection_methodbuilder_from_dynamic_method (&rmb, mb); @@ -11507,7 +11548,12 @@ mono_reflection_create_dynamic_method (MonoReflectionDynamicMethod *mb) klass = mb->owner ? mono_class_from_mono_type (mono_reflection_type_get_handle ((MonoReflectionType*)mb->owner)) : mono_defaults.object_class; - mb->mhandle = reflection_methodbuilder_to_mono_method (klass, &rmb, sig); + mb->mhandle = handle = reflection_methodbuilder_to_mono_method (klass, &rmb, sig); + release_data = g_new (DynamicMethodReleaseData, 1); + release_data->handle = handle; + release_data->domain = mono_object_get_domain ((MonoObject*)mb); + if (!mono_gc_reference_queue_add (queue, (MonoObject*)mb, release_data)) + g_free (release_data); /* Fix up refs entries pointing at us */ for (l = mb->referenced_by; l; l = l->next) { @@ -11533,16 +11579,6 @@ mono_reflection_create_dynamic_method (MonoReflectionDynamicMethod *mb) #endif /* DISABLE_REFLECTION_EMIT */ -void -mono_reflection_destroy_dynamic_method (MonoReflectionDynamicMethod *mb) -{ - g_assert (mb); - - if (mb->mhandle) - mono_runtime_free_method ( - mono_object_get_domain ((MonoObject*)mb), mb->mhandle); -} - /** * * mono_reflection_is_valid_dynamic_token:
mono/metadata/runtime.c+3 −0 modified@@ -39,5 +39,8 @@ void mono_runtime_shutdown (void) { mono_domain_foreach (fire_process_exit_event, NULL); + + /*From this point on, no more DM methods can be created. */ + mono_reflection_shutdown (); }
8eb1189099e0Implement a reference queue API.
2 files changed · +164 −0
mono/metadata/gc.c+141 −0 modified@@ -54,6 +54,7 @@ static gboolean finalizing_root_domain = FALSE; #define mono_finalizer_lock() EnterCriticalSection (&finalizer_mutex) #define mono_finalizer_unlock() LeaveCriticalSection (&finalizer_mutex) static CRITICAL_SECTION finalizer_mutex; +static CRITICAL_SECTION reference_queue_mutex; static GSList *domains_to_finalize= NULL; static MonoMList *threads_to_finalize = NULL; @@ -64,6 +65,7 @@ static void object_register_finalizer (MonoObject *obj, void (*callback)(void *, static void mono_gchandle_set_target (guint32 gchandle, MonoObject *obj); +static void reference_queue_proccess_all (void); #ifndef HAVE_NULL_GC static HANDLE pending_done_event; static HANDLE shutdown_event; @@ -1065,6 +1067,8 @@ finalizer_thread (gpointer unused) mono_attach_maybe_start (); #endif + reference_queue_proccess_all (); + if (domains_to_finalize) { mono_finalizer_lock (); if (domains_to_finalize) { @@ -1083,6 +1087,7 @@ finalizer_thread (gpointer unused) */ mono_gc_invoke_finalizers (); + SetEvent (pending_done_event); } @@ -1097,6 +1102,7 @@ mono_gc_init (void) InitializeCriticalSection (&allocator_section); InitializeCriticalSection (&finalizer_mutex); + InitializeCriticalSection (&reference_queue_mutex); MONO_GC_REGISTER_ROOT_FIXED (gc_handles [HANDLE_NORMAL].entries); MONO_GC_REGISTER_ROOT_FIXED (gc_handles [HANDLE_PINNED].entries); @@ -1174,6 +1180,7 @@ mono_gc_cleanup (void) DeleteCriticalSection (&handle_section); DeleteCriticalSection (&allocator_section); DeleteCriticalSection (&finalizer_mutex); + DeleteCriticalSection (&reference_queue_mutex); } #else @@ -1292,3 +1299,137 @@ mono_gc_alloc_mature (MonoVTable *vtable) return mono_object_new_specific (vtable); } #endif + + +static MonoReferenceQueue *ref_queues; + +static void +ref_list_remove_element (RefQueueEntry **prev, RefQueueEntry *element) +{ + do { + /* Guard if head is changed concurrently. */ + while (*prev != element) + prev = &(*prev)->next; + } while (prev && InterlockedCompareExchangePointer ((void*)prev, element->next, element) != element); +} + +static void +ref_list_push (RefQueueEntry **head, RefQueueEntry *value) +{ + RefQueueEntry *current; + do { + current = *head; + value->next = current; + } while (InterlockedCompareExchangePointer ((void*)head, value, current) != current); +} + +static void +reference_queue_proccess (MonoReferenceQueue *queue) +{ + RefQueueEntry **iter = &queue->queue; + RefQueueEntry *entry; + while ((entry = *iter)) { + if (queue->should_be_deleted || !mono_gc_weak_link_get (&entry->dis_link)) { + ref_list_remove_element (iter, entry); + mono_gc_weak_link_remove (&entry->dis_link); + queue->callback (entry->user_data); + g_free (entry); + } else { + iter = &entry->next; + } + } +} + +static void +reference_queue_proccess_all (void) +{ + MonoReferenceQueue **iter; + MonoReferenceQueue *queue = ref_queues; + for (; queue; queue = queue->next) + reference_queue_proccess (queue); + +restart: + EnterCriticalSection (&reference_queue_mutex); + for (iter = &ref_queues; *iter;) { + queue = *iter; + if (!queue->should_be_deleted) { + iter = &queue->next; + continue; + } + if (queue->queue) { + LeaveCriticalSection (&reference_queue_mutex); + reference_queue_proccess (queue); + goto restart; + } + *iter = queue->next; + g_free (queue); + } + LeaveCriticalSection (&reference_queue_mutex); +} + +/** + * mono_gc_reference_queue_new: + * @callback callback used when processing dead entries. + * + * Create a new reference queue used to process collected objects. + * A reference queue let you queue the pair (managed object, user data). + * Once the managed object is collected @callback will be called + * in the finalizer thread with 'user data' as argument. + * + * The callback is called without any locks held. + */ +MonoReferenceQueue* +mono_gc_reference_queue_new (mono_reference_queue_callback callback) +{ + MonoReferenceQueue *res = g_new0 (MonoReferenceQueue, 1); + res->callback = callback; + + EnterCriticalSection (&reference_queue_mutex); + res->next = ref_queues; + ref_queues = res; + LeaveCriticalSection (&reference_queue_mutex); + + return res; +} + +/** + * mono_gc_reference_queue_add: + * @queue the queue to add the reference to. + * @obj the object to be watched for collection + * @user_data parameter to be passed to the queue callback + * + * Queue an object to be watched for collection. + * + * @returns false if the queue is scheduled to be freed. + */ +gboolean +mono_gc_reference_queue_add (MonoReferenceQueue *queue, MonoObject *obj, void *user_data) +{ + RefQueueEntry *head; + RefQueueEntry *entry; + if (queue->should_be_deleted) + return FALSE; + + entry = g_new0 (RefQueueEntry, 1); + entry->user_data = user_data; + mono_gc_weak_link_add (&entry->dis_link, obj, TRUE); + ref_list_push (&queue->queue, entry); + return TRUE; +} + +/** + * mono_gc_reference_queue_free: + * @queue the queue that should be deleted. + * + * This operation signals that @queue should be deleted. This operation is deferred + * as it happens on the finalizer thread. + * + * After this call, no further objects can be queued. It's the responsibility of the + * caller to make sure that no further attempt to access queue will be made. + */ +void +mono_gc_reference_queue_free (MonoReferenceQueue *queue) +{ + queue->should_be_deleted = TRUE; +} +
mono/metadata/gc-internal.h+23 −0 modified@@ -335,5 +335,28 @@ gboolean mono_gc_precise_stack_mark_enabled (void) MONO_INTERNAL; FILE *mono_gc_get_logfile (void) MONO_INTERNAL; +typedef void (*mono_reference_queue_callback) (void *user_data); + +typedef struct _MonoReferenceQueue MonoReferenceQueue; +typedef struct _RefQueueEntry RefQueueEntry; + +struct _RefQueueEntry { + void *dis_link; + void *user_data; + RefQueueEntry *next; +}; + +struct _MonoReferenceQueue { + RefQueueEntry *queue; + mono_reference_queue_callback callback; + MonoReferenceQueue *next; + gboolean should_be_deleted; +}; + +MonoReferenceQueue* mono_gc_reference_queue_new (mono_reference_queue_callback callback) MONO_INTERNAL; +void mono_gc_reference_queue_free (MonoReferenceQueue *queue) MONO_INTERNAL; +gboolean mono_gc_reference_queue_add (MonoReferenceQueue *queue, MonoObject *obj, void *user_data) MONO_INTERNAL; + + #endif /* __MONO_METADATA_GC_INTERNAL_H__ */
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
13- openwall.com/lists/oss-security/2011/04/06/14nvdPatch
- bugzilla.novell.com/show_bug.cginvdPatch
- github.com/mono/mono/commit/3f8ee42b8c867d9a4c18c22657840d072cca5c3anvdPatch
- github.com/mono/mono/commit/89d1455a80ef13cddee5d79ec00c06055da3085cnvdPatch
- github.com/mono/mono/commit/8eb1189099e02372fd45ca1c67230eccf1edddc0nvdPatch
- secunia.com/advisories/44002nvdVendor Advisory
- secunia.com/advisories/44076nvdVendor Advisory
- www.mono-project.com/VulnerabilitiesnvdVendor Advisory
- www.vupen.com/english/advisories/2011/0904nvdVendor Advisory
- lists.opensuse.org/opensuse-updates/2011-04/msg00024.htmlnvd
- www.securityfocus.com/bid/47208nvd
- bugzilla.novell.com/show_bug.cginvd
- exchange.xforce.ibmcloud.com/vulnerabilities/66626nvd
News mentions
0No linked articles in our index yet.