{
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 *
* 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;
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:
* 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)
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 ();
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);
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 ();
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:
}
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);
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;
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);
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));
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));
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;
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))
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"));
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);
}
/*
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;
}
/*
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;
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
/* 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