X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fmetadata-verify.c;h=0ffb428a92d5b64c8396455bea201d06e2f82540;hb=3a5592eabcf055d5da5bafa46bff8fa72bd649c7;hp=61a00c69ee7c613fe6ded94b1c2f5974ae2c5e18;hpb=6d3f84a3c49e9c70f770cba236d4cc99b09516fc;p=mono.git diff --git a/mono/metadata/metadata-verify.c b/mono/metadata/metadata-verify.c index 61a00c69ee7..0ffb428a92d 100644 --- a/mono/metadata/metadata-verify.c +++ b/mono/metadata/metadata-verify.c @@ -217,7 +217,7 @@ typedef struct { typedef struct { const char *data; - guint32 size; + guint32 size, token; GSList *errors; int valid; MonoImage *image; @@ -250,6 +250,13 @@ typedef struct { } \ } while (0) +#define ADD_ERROR_NO_RETURN(__ctx, __msg) \ + do { \ + if ((__ctx)->report_error) \ + ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \ + (__ctx)->valid = 0; \ + } while (0) + #define ADD_ERROR(__ctx, __msg) \ do { \ if ((__ctx)->report_error) \ @@ -742,7 +749,7 @@ verify_metadata_header (VerifyContext *ctx) { int i; DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX); - guint32 offset; + guint32 offset, section_count; const char *ptr; offset = it.translated_offset; @@ -772,13 +779,14 @@ verify_metadata_header (VerifyContext *ctx) ptr = ctx->data + offset; //move to streams header - if (read16 (ptr + 2) < 3) + section_count = read16 (ptr + 2); + if (section_count < 3) ADD_ERROR (ctx, g_strdup_printf ("Metadata root section must have at least 3 streams (#~, #GUID and #Blob")); ptr += 4; offset += 4; - for (i = 0; i < 5; ++i) { + for (i = 0; i < section_count; ++i) { guint32 stream_off, stream_size; int string_size, stream_idx; @@ -814,8 +822,12 @@ verify_metadata_header (VerifyContext *ctx) stream_idx = GUID_STREAM; else if (!strncmp ("#~", ptr, 3)) stream_idx = TILDE_STREAM; - else - ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d invalid name %s", i, ptr)); + else { + ADD_WARNING (ctx, g_strdup_printf ("Metadata stream header %d invalid name %s", i, ptr)); + offset = pad4 (offset); + ptr = ctx->data + offset; + continue; + } if (ctx->metadata_streams [stream_idx].offset != 0) ADD_ERROR (ctx, g_strdup_printf ("Duplicated metadata stream header %s", ptr)); @@ -869,7 +881,7 @@ verify_tables_schema (VerifyContext *ctx) Unused: 0x1E 0x1F 0x2D-0x3F We don't care about the MS extensions.*/ if (i == 0x3 || i == 0x5 || i == 0x7 || i == 0x13 || i == 0x16) - ADD_ERROR (ctx, g_strdup_printf ("The metadata verifies doesn't support MS specific table %x", i)); + ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support MS specific table %x", i)); if (i == 0x1E || i == 0x1F || i >= 0x2D) ADD_ERROR (ctx, g_strdup_printf ("Invalid table %x", i)); ++count; @@ -1255,6 +1267,12 @@ parse_generic_inst (VerifyContext *ctx, const char **_ptr, const char *end) if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token)) FAIL (ctx, g_strdup_printf ("GenericInst: invalid TypeDefOrRef token %x", token)); + if (ctx->token) { + if (mono_metadata_token_index (ctx->token) == get_coded_index_token (TYPEDEF_OR_REF_DESC, token) && + mono_metadata_token_table (ctx->token) == get_coded_index_table (TYPEDEF_OR_REF_DESC, token)) + FAIL (ctx, g_strdup_printf ("Type: Recurside generic instance specification (%x). A type signature can't reference itself", ctx->token)); + } + if (!safe_read_cint (count, ptr, end)) FAIL (ctx, g_strdup ("GenericInst: Not enough room for argument count")); @@ -1307,6 +1325,11 @@ parse_type (VerifyContext *ctx, const char **_ptr, const char *end) if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token)) FAIL (ctx, g_strdup_printf ("Type: invalid TypeDefOrRef token %x", token)); + if (ctx->token) { + if (mono_metadata_token_index (ctx->token) == get_coded_index_token (TYPEDEF_OR_REF_DESC, token) && + mono_metadata_token_table (ctx->token) == get_coded_index_table (TYPEDEF_OR_REF_DESC, token)) + FAIL (ctx, g_strdup_printf ("Type: Recurside type specification (%x). A type signature can't reference itself", ctx->token)); + } break; case MONO_TYPE_VAR: @@ -1672,6 +1695,11 @@ is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset) --ptr; if (signature == 0x07) return parse_locals_signature (ctx, &ptr, end); + + /*F# and managed C++ produce standalonesig for fields even thou the spec doesn't mention it.*/ + if (signature == 0x06) + return parse_field (ctx, &ptr, end); + return parse_method_signature (ctx, &ptr, end, TRUE, TRUE); } @@ -1721,7 +1749,7 @@ is_valid_typespec_blob (VerifyContext *ctx, guint32 offset) } static gboolean -is_valid_methodspec_blog (VerifyContext *ctx, guint32 offset) +is_valid_methodspec_blob (VerifyContext *ctx, guint32 offset) { int size = 0; const char *ptr = NULL, *end; @@ -2083,8 +2111,10 @@ verify_typedef_table_full (VerifyContext *ctx) mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE); if (i == 0) { - if (data [MONO_TYPEDEF_EXTENDS] != 0) + /*XXX it's ok if extends object, or anything at all, actually. */ + /*if (data [MONO_TYPEDEF_EXTENDS] != 0) ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special type must have a null extend field")); + */ continue; } @@ -2190,8 +2220,8 @@ verify_field_table_full (VerifyContext *ctx) } } -/*bits 6,8,9,10,11,13,14,15*/ -#define INVALID_METHOD_IMPLFLAG_BITS ((1 << 6) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15)) +/*bits 8,9,10,11,13,14,15*/ +#define INVALID_METHOD_IMPLFLAG_BITS ((1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15)) static void verify_method_table (VerifyContext *ctx) { @@ -2240,6 +2270,8 @@ verify_method_table (VerifyContext *ctx) if (flags & METHOD_ATTRIBUTE_ABSTRACT) { if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i)); + if (flags & METHOD_ATTRIBUTE_FINAL) + ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and Final", i)); if (!(flags & METHOD_ATTRIBUTE_VIRTUAL)) ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i)); } @@ -2887,10 +2919,11 @@ verify_typespec_table_full (VerifyContext *ctx) for (i = 0; i < table->rows; ++i) { mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE); - + ctx->token = (i + 1) | MONO_TOKEN_TYPE_SPEC; if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE])) ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE])); } + ctx->token = 0; } #define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 6) | (1 << 8) | (1 << 9) | (1 << 10)) @@ -3191,7 +3224,7 @@ verify_method_spec_table_full (VerifyContext *ctx) for (i = 0; i < table->rows; ++i) { mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE); - if (!is_valid_methodspec_blog (ctx, data [MONO_METHODSPEC_SIGNATURE])) + if (!is_valid_methodspec_blob (ctx, data [MONO_METHODSPEC_SIGNATURE])) ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE])); } } @@ -3217,6 +3250,104 @@ verify_generic_param_constraint_table (VerifyContext *ctx) } } + +typedef struct { + const char *name; + const char *name_space; + guint32 resolution_scope; +} TypeDefUniqueId; + +static guint +typedef_hash (gconstpointer _key) +{ + const TypeDefUniqueId *key = _key; + return g_str_hash (key->name) ^ g_str_hash (key->name_space) ^ key->resolution_scope; /*XXX better salt the int key*/ +} + +static gboolean +typedef_equals (gconstpointer _a, gconstpointer _b) +{ + const TypeDefUniqueId *a = _a; + const TypeDefUniqueId *b = _b; + return !strcmp (a->name, b->name) && !strcmp (a->name_space, b->name_space) && a->resolution_scope == b->resolution_scope; +} + +static void +verify_typedef_table_global_constraints (VerifyContext *ctx) +{ + int i; + guint32 data [MONO_TYPEDEF_SIZE]; + guint32 nested_data [MONO_NESTED_CLASS_SIZE]; + MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF]; + MonoTableInfo *nested_table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS]; + GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL); + + for (i = 0; i < table->rows; ++i) { + guint visibility; + TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1); + mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE); + + type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAME]); + type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAMESPACE]); + type->resolution_scope = 0; + + visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK; + if (visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) { + int res = search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1); + g_assert (res >= 0); + + mono_metadata_decode_row (nested_table, res, nested_data, MONO_NESTED_CLASS_SIZE); + type->resolution_scope = nested_data [MONO_NESTED_CLASS_ENCLOSING]; + } + + if (g_hash_table_lookup (unique_types, type)) { + ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("TypeDef table row %d has duplicate for tuple (%s,%s,%x)", i, type->name, type->name_space, type->resolution_scope)); + g_hash_table_destroy (unique_types); + g_free (type); + return; + } + g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1)); + } + + g_hash_table_destroy (unique_types); +} + +static void +verify_typeref_table_global_constraints (VerifyContext *ctx) +{ + int i; + guint32 data [MONO_TYPEREF_SIZE]; + MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF]; + GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL); + + for (i = 0; i < table->rows; ++i) { + TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1); + mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE); + + type->resolution_scope = data [MONO_TYPEREF_SCOPE]; + type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAME]); + type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAMESPACE]); + + if (g_hash_table_lookup (unique_types, type)) { + ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("TypeRef table row %d has duplicate for tuple (%s,%s,%x)", i, type->name, type->name_space, type->resolution_scope)); + g_hash_table_destroy (unique_types); + g_free (type); + return; + } + g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1)); + } + + g_hash_table_destroy (unique_types); +} + +static void +verify_tables_data_global_constraints (VerifyContext *ctx) +{ + verify_typeref_table_global_constraints (ctx); + CHECK_ERROR (); + verify_typedef_table_global_constraints (ctx); +} + static void verify_tables_data (VerifyContext *ctx) { @@ -3307,6 +3438,8 @@ verify_tables_data (VerifyContext *ctx) verify_method_spec_table (ctx); CHECK_ERROR (); verify_generic_param_constraint_table (ctx); + CHECK_ERROR (); + verify_tables_data_global_constraints (ctx); } static void @@ -3528,7 +3661,7 @@ mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSL } gboolean -mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, GSList **error_list) +mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list) { VerifyContext ctx; @@ -3537,6 +3670,7 @@ mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, GSLis init_verify_context (&ctx, image, error_list); ctx.stage = STAGE_TABLES; + ctx.token = token; is_valid_typespec_blob (&ctx, offset); return cleanup_context (&ctx, error_list); @@ -3553,10 +3687,75 @@ mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSL init_verify_context (&ctx, image, error_list); ctx.stage = STAGE_TABLES; - is_valid_methodspec_blog (&ctx, offset); + is_valid_methodspec_blob (&ctx, offset); + return cleanup_context (&ctx, error_list); +} + +static void +verify_user_string (VerifyContext *ctx, guint32 offset) +{ + OffsetAndSize heap_us = get_metadata_stream (ctx, &ctx->image->heap_us); + guint32 entry_size, bytes; + + if (heap_us.size < offset) + ADD_ERROR (ctx, g_strdup ("User string offset beyond heap_us size")); + + if (!decode_value (ctx->data + offset + heap_us.offset, heap_us.size - heap_us.offset, &entry_size, &bytes)) + ADD_ERROR (ctx, g_strdup ("Could not decode user string blob size")); + + if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes)) + ADD_ERROR (ctx, g_strdup ("User string size overflow")); + + entry_size += bytes; + + if (ADD_IS_GREATER_OR_OVF (offset, entry_size, heap_us.size)) + ADD_ERROR (ctx, g_strdup ("User string oveflow heap_us")); +} + +gboolean +mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list) +{ + VerifyContext ctx; + + if (!mono_verifier_is_enabled_for_image (image)) + return TRUE; + + init_verify_context (&ctx, image, error_list); + ctx.stage = STAGE_TABLES; + + verify_user_string (&ctx, offset); + return cleanup_context (&ctx, error_list); } +gboolean +mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature) +{ + MonoMethodSignature *original_sig; + if (!mono_verifier_is_enabled_for_image (image)) + return TRUE; + + original_sig = mono_method_signature (method); + if (original_sig->call_convention == MONO_CALL_VARARG) { + if (original_sig->hasthis != signature->hasthis) + return FALSE; + if (original_sig->call_convention != signature->call_convention) + return FALSE; + if (original_sig->explicit_this != signature->explicit_this) + return FALSE; + if (original_sig->call_convention != signature->call_convention) + return FALSE; + if (original_sig->pinvoke != signature->pinvoke) + return FALSE; + if (original_sig->sentinelpos != signature->sentinelpos) + return FALSE; + } else if (!mono_metadata_signature_equal (signature, original_sig)) { + return FALSE; + } + + return TRUE; +} + #else gboolean mono_verifier_verify_table_data (MonoImage *image, GSList **error_list) @@ -3613,7 +3812,7 @@ mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSL } gboolean -mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, GSList **error_list) +mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list) { return TRUE; } @@ -3624,4 +3823,17 @@ mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSL return TRUE; } +gboolean +mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list) +{ + return TRUE; +} + +gboolean +mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature) +{ + return TRUE; +} + + #endif /* DISABLE_VERIFIER */