X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fverify.c;h=223a8f94ebedc0d76b048e2f2312fffe5159134c;hb=9ea6bba25e0815221a5afc3629120dea3fa07b28;hp=180c80daa7c5913bca2e0be80e033debe54bd917;hpb=a8ab40d5d7313e8f3cab210f724aded303e04c94;p=mono.git diff --git a/mono/metadata/verify.c b/mono/metadata/verify.c index 180c80daa7c..223a8f94ebe 100644 --- a/mono/metadata/verify.c +++ b/mono/metadata/verify.c @@ -366,7 +366,7 @@ token_bounds_check (MonoImage *image, guint32 token) { if (image->dynamic) return mono_reflection_is_valid_dynamic_token ((MonoDynamicImage*)image, token); - return image->tables [mono_metadata_token_table (token)].rows >= mono_metadata_token_index (token); + return image->tables [mono_metadata_token_table (token)].rows >= mono_metadata_token_index (token) && mono_metadata_token_index (token) > 0; } static MonoType * @@ -480,7 +480,7 @@ mono_class_has_default_constructor (MonoClass *klass) * this function checks for VAR and MVAR types that are invalid under the current verifier, */ static gboolean -mono_type_is_valid_type_in_context (MonoType *type, MonoGenericContext *context) +mono_type_is_valid_type_in_context_full (MonoType *type, MonoGenericContext *context, gboolean check_gtd) { int i; MonoGenericInst *inst; @@ -495,17 +495,17 @@ mono_type_is_valid_type_in_context (MonoType *type, MonoGenericContext *context) return FALSE; break; case MONO_TYPE_SZARRAY: - return mono_type_is_valid_type_in_context (&type->data.klass->byval_arg, context); + return mono_type_is_valid_type_in_context_full (&type->data.klass->byval_arg, context, TRUE); case MONO_TYPE_ARRAY: - return mono_type_is_valid_type_in_context (&type->data.array->eklass->byval_arg, context); + return mono_type_is_valid_type_in_context_full (&type->data.array->eklass->byval_arg, context, TRUE); case MONO_TYPE_PTR: - return mono_type_is_valid_type_in_context (type->data.type, context); + return mono_type_is_valid_type_in_context_full (type->data.type, context, TRUE); case MONO_TYPE_GENERICINST: inst = type->data.generic_class->context.class_inst; if (!inst->is_open) break; for (i = 0; i < inst->type_argc; ++i) - if (!mono_type_is_valid_type_in_context (inst->type_argv [i], context)) + if (!mono_type_is_valid_type_in_context_full (inst->type_argv [i], context, TRUE)) return FALSE; break; case MONO_TYPE_CLASS: @@ -516,17 +516,26 @@ mono_type_is_valid_type_in_context (MonoType *type, MonoGenericContext *context) * Fixing the type decoding is really tricky since under some cases this behavior is needed, for example, to * have a 'class' type pointing to a 'genericinst' class. * - * For the runtime these non canonical (weird) encodings work fine, they worst they can cause is some + * For the runtime these non canonical (weird) encodings work fine, the worst they can cause is some * reflection oddities which are harmless - to security at least. */ if (klass->byval_arg.type != type->type) - return mono_type_is_valid_type_in_context (&klass->byval_arg, context); + return mono_type_is_valid_type_in_context_full (&klass->byval_arg, context, check_gtd); + + if (check_gtd && klass->generic_container) + return FALSE; break; } } return TRUE; } +static gboolean +mono_type_is_valid_type_in_context (MonoType *type, MonoGenericContext *context) +{ + return mono_type_is_valid_type_in_context_full (type, context, FALSE); +} + /*This function returns NULL if the type is not instantiatable*/ static MonoType* verifier_inflate_type (VerifyContext *ctx, MonoType *type, MonoGenericContext *context) @@ -892,12 +901,18 @@ verifier_load_field (VerifyContext *ctx, int token, MonoClass **out_klass, const MonoClassField *field; MonoClass *klass = NULL; - if (!IS_FIELD_DEF_OR_REF (token) || !token_bounds_check (ctx->image, token)) { - ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid field token 0x%08x for %s at 0x%04x", token, opcode, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE); - return NULL; + if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) { + field = mono_method_get_wrapper_data (ctx->method, (guint32)token); + klass = field ? field->parent : NULL; + } else { + if (!IS_FIELD_DEF_OR_REF (token) || !token_bounds_check (ctx->image, token)) { + ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid field token 0x%08x for %s at 0x%04x", token, opcode, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE); + return NULL; + } + + field = mono_field_from_token (ctx->image, token, &klass, ctx->generic_context); } - field = mono_field_from_token (ctx->image, token, &klass, ctx->generic_context); if (!field || !field->parent || !klass || mono_loader_get_last_error ()) { ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Cannot load field from token 0x%08x for %s at 0x%04x", token, opcode, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE); mono_loader_clear_error (); @@ -921,13 +936,17 @@ verifier_load_field (VerifyContext *ctx, int token, MonoClass **out_klass, const static MonoMethod* verifier_load_method (VerifyContext *ctx, int token, const char *opcode) { MonoMethod* method; - - if (!IS_METHOD_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) { - ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid method token 0x%08x for %s at 0x%04x", token, opcode, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE); - return NULL; - } - method = mono_get_method_full (ctx->image, token, NULL, ctx->generic_context); + if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) { + method = mono_method_get_wrapper_data (ctx->method, (guint32)token); + } else { + if (!IS_METHOD_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) { + ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid method token 0x%08x for %s at 0x%04x", token, opcode, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE); + return NULL; + } + + method = mono_get_method_full (ctx->image, token, NULL, ctx->generic_context); + } if (!method || mono_loader_get_last_error ()) { ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Cannot load method from token 0x%08x for %s at 0x%04x", token, opcode, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE); @@ -945,13 +964,17 @@ static MonoType* verifier_load_type (VerifyContext *ctx, int token, const char *opcode) { MonoType* type; - if (!IS_TYPE_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) { - ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid type token 0x%08x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE); - return NULL; + if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) { + MonoClass *class = mono_method_get_wrapper_data (ctx->method, (guint32)token); + type = class ? &class->byval_arg : NULL; + } else { + if (!IS_TYPE_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) { + ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid type token 0x%08x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE); + return NULL; + } + type = mono_type_get_full (ctx->image, token, ctx->generic_context); } - type = mono_type_get_full (ctx->image, token, ctx->generic_context); - if (!type || mono_loader_get_last_error ()) { ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Cannot load type from token 0x%08x for %s at 0x%04x", token, opcode, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE); mono_loader_clear_error (); @@ -2350,6 +2373,8 @@ mono_delegate_type_equal (MonoType *target, MonoType *candidate) return candidate->type == target->type; case MONO_TYPE_PTR: + if (candidate->type != MONO_TYPE_PTR) + return FALSE; return mono_delegate_type_equal (target->data.type, candidate->data.type); case MONO_TYPE_FNPTR: @@ -3055,6 +3080,9 @@ do_invoke_method (VerifyContext *ctx, int method_token, gboolean virtual) } if (sig->ret->type != MONO_TYPE_VOID) { + if (!mono_type_is_valid_in_context (ctx, sig->ret)) + return; + if (check_overflow (ctx)) { value = stack_push (ctx); set_stack_value (ctx, value, sig->ret, FALSE); @@ -3388,25 +3416,33 @@ do_load_token (VerifyContext *ctx, int token) if (!check_overflow (ctx)) return; - switch (token & 0xff000000) { - case MONO_TOKEN_TYPE_DEF: - case MONO_TOKEN_TYPE_REF: - case MONO_TOKEN_TYPE_SPEC: - case MONO_TOKEN_FIELD_DEF: - case MONO_TOKEN_METHOD_DEF: - case MONO_TOKEN_METHOD_SPEC: - case MONO_TOKEN_MEMBER_REF: - if (!token_bounds_check (ctx->image, token)) { - ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Table index out of range 0x%x for token %x for ldtoken at 0x%04x", mono_metadata_token_index (token), token, ctx->ip_offset)); + if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) { + handle = mono_method_get_wrapper_data (ctx->method, token); + handle_class = mono_method_get_wrapper_data (ctx->method, token + 1); + if (handle_class == mono_defaults.typehandle_class) + handle = &((MonoClass*)handle)->byval_arg; + } else { + switch (token & 0xff000000) { + case MONO_TOKEN_TYPE_DEF: + case MONO_TOKEN_TYPE_REF: + case MONO_TOKEN_TYPE_SPEC: + case MONO_TOKEN_FIELD_DEF: + case MONO_TOKEN_METHOD_DEF: + case MONO_TOKEN_METHOD_SPEC: + case MONO_TOKEN_MEMBER_REF: + if (!token_bounds_check (ctx->image, token)) { + ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Table index out of range 0x%x for token %x for ldtoken at 0x%04x", mono_metadata_token_index (token), token, ctx->ip_offset)); + return; + } + break; + default: + ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid table 0x%x for token 0x%x for ldtoken at 0x%04x", mono_metadata_token_table (token), token, ctx->ip_offset)); return; } - break; - default: - ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid table 0x%x for token 0x%x for ldtoken at 0x%04x", mono_metadata_token_table (token), token, ctx->ip_offset)); - return; + + handle = mono_ldtoken (ctx->image, token, &handle_class, ctx->generic_context); } - handle = mono_ldtoken (ctx->image, token, &handle_class, ctx->generic_context); if (!handle) { ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid token 0x%x for ldtoken at 0x%04x", token, ctx->ip_offset)); return; @@ -3576,7 +3612,7 @@ do_newobj (VerifyContext *ctx, int token) if (method->klass->flags & (TYPE_ATTRIBUTE_ABSTRACT | TYPE_ATTRIBUTE_INTERFACE)) CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Trying to instantiate an abstract or interface type at 0x%04x", ctx->ip_offset)); - if (!mono_method_can_access_method_full (ctx->method, method, NULL)) { + if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, NULL)) { char *from = mono_method_full_name (ctx->method, TRUE); char *to = mono_method_full_name (method, TRUE); CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Constructor %s not visible from %s at 0x%04x", to, from, ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS); @@ -4116,13 +4152,21 @@ do_load_function_ptr (VerifyContext *ctx, guint32 token, gboolean virtual) if (!virtual && !check_overflow (ctx)) return; - if (!IS_METHOD_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) { - ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid token %x for ldftn at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE); - return; - } + if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) { + method = mono_method_get_wrapper_data (ctx->method, (guint32)token); + if (!method) { + ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid token %x for ldftn at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE); + return; + } + } else { + if (!IS_METHOD_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) { + ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid token %x for ldftn at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE); + return; + } - if (!(method = verifier_load_method (ctx, token, virtual ? "ldvirtfrn" : "ldftn"))) - return; + if (!(method = verifier_load_method (ctx, token, virtual ? "ldvirtfrn" : "ldftn"))) + return; + } if (mono_method_is_constructor (method)) CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use ldftn with a constructor at 0x%04x", ctx->ip_offset)); @@ -4140,7 +4184,7 @@ do_load_function_ptr (VerifyContext *ctx, guint32 token, gboolean virtual) CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Unexpected object for ldvirtftn at 0x%04x", ctx->ip_offset)); } - if (!mono_method_can_access_method_full (ctx->method, method, NULL)) + if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, NULL)) CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Loaded method is not visible for ldftn/ldvirtftn at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS); top = stack_push_val(ctx, TYPE_PTR, mono_type_create_fnptr_from_mono_method (ctx, method)); @@ -4151,11 +4195,6 @@ static void do_sizeof (VerifyContext *ctx, int token) { MonoType *type; - - if (!IS_TYPE_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) { - ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid type token %x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE); - return; - } if (!(type = verifier_load_type (ctx, token, "sizeof"))) return; @@ -4201,16 +4240,18 @@ static void do_ldstr (VerifyContext *ctx, guint32 token) { GSList *error = NULL; - if (mono_metadata_token_code (token) != MONO_TOKEN_STRING) { - ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid string token %x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE); - return; - } + if (ctx->method->wrapper_type == MONO_WRAPPER_NONE && !ctx->image->dynamic) { + if (mono_metadata_token_code (token) != MONO_TOKEN_STRING) { + ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid string token %x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE); + return; + } - if (!ctx->image->dynamic && !mono_verifier_verify_string_signature (ctx->image, mono_metadata_token_index (token), &error)) { - if (error) - ctx->list = g_slist_concat (ctx->list, error); - ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid string index %x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE); - return; + if (!mono_verifier_verify_string_signature (ctx->image, mono_metadata_token_index (token), &error)) { + if (error) + ctx->list = g_slist_concat (ctx->list, error); + ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid string index %x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE); + return; + } } if (check_overflow (ctx)) @@ -4569,6 +4610,12 @@ mono_method_verify (MonoMethod *method, int level) finish_collect_stats (); return ctx.list; } + if (!method->is_generic && !method->klass->is_generic && ctx.signature->has_type_parameters) { + ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Method and signature don't match in terms of genericity")); + finish_collect_stats (); + return ctx.list; + } + ctx.header = mono_method_get_header (method); if (!ctx.header) { ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Could not decode method header")); @@ -5729,7 +5776,7 @@ mono_verify_corlib () gboolean mono_verifier_is_enabled_for_method (MonoMethod *method) { - return mono_verifier_is_enabled_for_class (method->klass) && method->wrapper_type == MONO_WRAPPER_NONE; + return mono_verifier_is_enabled_for_class (method->klass) && (method->wrapper_type == MONO_WRAPPER_NONE || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD); } /* @@ -5748,10 +5795,14 @@ mono_verifier_is_enabled_for_image (MonoImage *image) return verify_all || verifier_mode > MONO_VERIFIER_MODE_OFF; } +/* + * Dynamic methods are not considered full trust since if the user is trusted and need to + * generate unsafe code, make the method skip verification - this is a known good way to do it. + */ gboolean mono_verifier_is_method_full_trust (MonoMethod *method) { - return mono_verifier_is_class_full_trust (method->klass); + return mono_verifier_is_class_full_trust (method->klass) && !method->dynamic; } /* @@ -6015,6 +6066,13 @@ mono_verifier_verify_class (MonoClass *class) return FALSE; if (!class->generic_class && class->parent->generic_container) return FALSE; + if (class->parent->generic_class && !class->generic_class) { + MonoGenericContext *context = mono_class_get_context (class); + if (class->generic_container) + context = &class->generic_container->context; + if (!mono_type_is_valid_type_in_context (&class->parent->byval_arg, context)) + return FALSE; + } } if (class->generic_container && (class->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) return FALSE; @@ -6032,6 +6090,21 @@ mono_verifier_verify_class (MonoClass *class) return FALSE; return TRUE; } + +gboolean +mono_verifier_class_is_valid_generic_instantiation (MonoClass *class) +{ + return mono_class_is_valid_generic_instantiation (NULL, class); +} + +gboolean +mono_verifier_is_method_valid_generic_instantiation (MonoMethod *method) +{ + if (!method->is_inflated) + return TRUE; + return mono_method_is_valid_generic_instantiation (NULL, method); +} + #else gboolean @@ -6097,4 +6170,18 @@ mono_free_verify_list (GSList *list) /* will always be null if verifier is disabled */ } +gboolean +mono_verifier_class_is_valid_generic_instantiation (MonoClass *class) +{ + return TRUE; +} + +gboolean +mono_verifier_is_method_valid_generic_instantiation (MonoMethod *method) +{ + return TRUE; +} + + + #endif