2009-04-28 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / metadata / metadata-verify.c
index 15cb0cfb05e53f3280afb9d3c49f4bacdc27a3cc..04f13567f7c970e3f2d3c298379917c0a912b16d 100644 (file)
@@ -38,6 +38,8 @@
  TODO verify in the CLI header entry point and resources
  TODO implement null token typeref validation  
  TODO verify table wide invariants for typedef (sorting and uniqueness)
+ TODO implement proper authenticode data directory validation
+ TODO verify properties that require multiple tables to be valid 
  FIXME use subtraction based bounds checking to avoid overflows
  FIXME get rid of metadata_streams and other fields from VerifyContext
 */
@@ -49,6 +51,7 @@
 #endif
 
 #define INVALID_OFFSET ((guint32)-1)
+#define INVALID_ADDRESS 0xffffffff
 
 enum {
        STAGE_PE,
@@ -59,6 +62,7 @@ enum {
 enum {
        IMPORT_TABLE_IDX = 1, 
        RESOURCE_TABLE_IDX = 2,
+       CERTIFICATE_TABLE_IDX = 4,
        RELOCATION_TABLE_IDX = 5,
        IAT_IDX = 12,
        CLI_HEADER_IDX = 14,
@@ -490,6 +494,11 @@ load_data_directories (VerifyContext *ctx)
                guint32 rva = read32 (ptr);
                guint32 size = read32 (ptr + 4);
 
+               /*LAMESPEC the authenticode data directory format is different. We don't support CAS, so lets ignore for now.*/
+               if (i == CERTIFICATE_TABLE_IDX) {
+                       ptr += 8;
+                       continue;
+               }
                if ((rva != 0 || size != 0) && !is_valid_data_directory (i))
                        ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d", i));
 
@@ -855,7 +864,7 @@ get_metadata_stream (VerifyContext *ctx, MonoStreamHeader *header)
 }
 
 static gboolean
-is_valid_non_empty_string (VerifyContext *ctx, guint32 offset)
+is_valid_string_full (VerifyContext *ctx, guint32 offset, gboolean allow_empty)
 {
        OffsetAndSize strings = get_metadata_stream (ctx, &ctx->image->heap_strings);
        glong length;
@@ -868,7 +877,19 @@ is_valid_non_empty_string (VerifyContext *ctx, guint32 offset)
 
        if (!mono_utf8_validate_and_len_with_bounds (data + offset, strings.size - offset, &length, NULL))
                return FALSE;
-       return length > 0;
+       return allow_empty || length > 0;
+}
+
+static gboolean
+is_valid_string (VerifyContext *ctx, guint32 offset)
+{
+       return is_valid_string_full (ctx, offset, TRUE);
+}
+
+static gboolean
+is_valid_non_empty_string (VerifyContext *ctx, guint32 offset)
+{
+       return is_valid_string_full (ctx, offset, FALSE);
 }
 
 static gboolean
@@ -879,7 +900,7 @@ is_valid_guid (VerifyContext *ctx, guint32 offset)
 }
 
 static guint32
-get_coded_index_token (VerifyContext *ctx, int token_kind, guint32 coded_token)
+get_coded_index_token (int token_kind, guint32 coded_token)
 {
        guint32 bits = coded_index_desc [token_kind];
        return coded_token >> bits;
@@ -954,6 +975,13 @@ search_sorted_table (VerifyContext *ctx, int table, int column, guint32 coded_to
        return (res - base) / tinfo->rows;
 }
 
+/*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
+static const char*
+get_string_ptr (VerifyContext *ctx, guint offset)
+{
+       return ctx->image->heap_strings.data + offset;
+}
+
 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
 static int
 string_cmp (VerifyContext *ctx, const char *str, guint offset)
@@ -961,7 +989,7 @@ string_cmp (VerifyContext *ctx, const char *str, guint offset)
        if (offset == 0)
                return strcmp (str, "");
 
-       return strcmp (str, ctx->image->heap_strings.data + offset);
+       return strcmp (str, get_string_ptr (ctx, offset));
 }
 
 static gboolean
@@ -970,6 +998,29 @@ typedef_is_system_object (VerifyContext *ctx, guint32 *data)
        return ctx->is_corlib && !string_cmp (ctx, "System", data [MONO_TYPEDEF_NAME]) && !string_cmp (ctx, "Object", data [MONO_TYPEDEF_NAMESPACE]);
 }
 
+static gboolean
+is_valid_field_signature (VerifyContext *ctx, guint32 offset)
+{
+       OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
+       //TODO do proper verification
+       return blob.size >= 2 && blob.size - 2 >= offset;
+}
+
+static gboolean
+is_valid_method_signature (VerifyContext *ctx, guint32 offset)
+{
+       OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
+       //TODO do proper verification
+       return blob.size >= 2 && blob.size - 2 >= offset;
+}
+
+static gboolean
+is_valid_method_header (VerifyContext *ctx, guint32 rva)
+{
+       //TODO do proper method header validation
+       return mono_cli_rva_image_map (ctx->image, rva) != INVALID_ADDRESS;
+}
+
 static void
 verify_module_table (VerifyContext *ctx)
 {
@@ -1006,7 +1057,7 @@ verify_typeref_table (VerifyContext *ctx)
                if (!is_valid_coded_index (ctx, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
                        ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d coded index 0x%08x", i, data [MONO_TYPEREF_SCOPE]));
                
-               if (!get_coded_index_token (ctx, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
+               if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
                        ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", i));
 
                if (!data [MONO_TYPEREF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAME]))
@@ -1066,7 +1117,7 @@ verify_typedef_table (VerifyContext *ctx)
                                if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
                                        ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
        
-                               if (!get_coded_index_token (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS])) 
+                               if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS])) 
                                        ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
                        }
                }
@@ -1074,15 +1125,22 @@ verify_typedef_table (VerifyContext *ctx)
                if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
                        ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
 
+               if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
+
                if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
                        ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x can't be smaller than of previous row 0x%08x", i, data [MONO_TYPEDEF_FIELD_LIST], fieldlist));
 
                if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
                        ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
 
+               if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
+
                if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
                        ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x can't be smaller than of previous row 0x%08x", i, data [MONO_TYPEDEF_METHOD_LIST], methodlist));
 
+
                fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
                methodlist = data [MONO_TYPEDEF_METHOD_LIST];
        }
@@ -1094,9 +1152,15 @@ static void
 verify_field_table (VerifyContext *ctx)
 {
        MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
-       guint32 data [MONO_FIELD_SIZE], flags;
+       guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
        int i;
 
+       module_field_list = (guint32)-1;
+       if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
+               MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
+               module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
+       }
+       
        for (i = 0; i < table->rows; ++i) {
                mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
                flags = data [MONO_FIELD_FLAGS];
@@ -1124,6 +1188,10 @@ verify_field_table (VerifyContext *ctx)
                                search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
                        ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
 
+               if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
+                               search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
+
                if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
                                search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
                        ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
@@ -1131,6 +1199,236 @@ verify_field_table (VerifyContext *ctx)
                if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
                        ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
 
+               //TODO verify contant flag
+               if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
+
+               if (i + 1 < module_field_list) {
+                       guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
+                       if (!(flags & FIELD_ATTRIBUTE_STATIC))
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
+                       if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
+               }
+       }
+}
+
+/*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))
+static void
+verify_method_table (VerifyContext *ctx)
+{
+       MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
+       guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
+       guint32 paramlist = 1;
+       gboolean is_ctor, is_cctor;
+       const char *name;
+       int i;
+
+       module_method_list = (guint32)-1;
+       if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
+               MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
+               module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
+       }
+
+       for (i = 0; i < table->rows; ++i) {
+               mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
+               rva = data [MONO_METHOD_RVA];
+               implflags = data [MONO_METHOD_IMPLFLAGS];
+               flags = data [MONO_METHOD_FLAGS];
+               access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
+               code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
+               
+
+               if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
+
+               if (access == 0x7)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
+
+               if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
+
+               name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
+               is_ctor = !strcmp (".ctor", name);
+               is_cctor = !strcmp (".cctor", name);
+
+               if ((is_ctor || is_cctor) &&
+                       search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
+
+               if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
+               
+               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_VIRTUAL))
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
+               }
+
+               if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
+
+               if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
+
+               //XXX no checks against cas stuff 10,11,12,13)
+
+               //TODO check iface with .ctor (15,16)
+
+               if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token %08x", i, data [MONO_METHOD_SIGNATURE]));
+
+               if (i + 1 < module_method_list) {
+                       if (!(flags & METHOD_ATTRIBUTE_STATIC))
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
+                       if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
+                       if (!(access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED || access == METHOD_ATTRIBUTE_PUBLIC || access == METHOD_ATTRIBUTE_PRIVATE))
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public or Private", i));
+               }
+
+               //TODO check valuetype for synchronized
+
+               if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
+
+               if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && (flags & METHOD_ATTRIBUTE_VIRTUAL))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
+
+               if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && 
+                               !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
+
+               if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
+
+               //TODO check signature contents
+
+               if (rva) {
+                       if (flags & METHOD_ATTRIBUTE_ABSTRACT)
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", i));
+                       if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
+                       if (!is_valid_method_header (ctx, rva))
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
+               } else {
+                       if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
+               }
+
+               if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
+                       if (rva)
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
+                       if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
+               }
+               if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
+
+               if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
+
+               if (data [MONO_METHOD_PARAMLIST] == 0)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
+
+               if (data [MONO_METHOD_PARAMLIST] < paramlist)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x can't be smaller than of previous row 0x%08x", i, data [MONO_METHOD_PARAMLIST], paramlist));
+
+               if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
+
+               paramlist = data [MONO_METHOD_PARAMLIST];
+
+       }
+}
+
+static guint32
+get_next_param_count (VerifyContext *ctx, guint32 *current_method)
+{
+       MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
+       guint32 row = *current_method;
+       guint32 paramlist, tmp;
+
+
+       paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
+       while (row < table->rows) {
+               tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
+               if (tmp > paramlist) {
+                       *current_method = row;
+                       return tmp - paramlist;
+               }
+               ++row;
+       }
+
+       /*no more methods, all params apply to the last one*/
+       *current_method = table->rows;
+       return (guint32)-1;
+}
+
+
+#define INVALID_PARAM_FLAGS_BITS ((1 << 2) | (1 << 3) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 14) | (1 << 15))
+static void
+verify_param_table (VerifyContext *ctx)
+{
+       MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
+       guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
+       gboolean first_param = TRUE;
+       int i;
+
+       remaining_params = get_next_param_count (ctx, &current_method);
+
+       for (i = 0; i < table->rows; ++i) {
+               mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
+               flags = data [MONO_PARAM_FLAGS];
+
+               if (flags & INVALID_PARAM_FLAGS_BITS)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
+
+               if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
+                       if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
+               } else {
+                       if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
+               }
+
+               if ((flags & PARAM_ATTRIBUTE_HAS_FIELD_MARSHAL) && search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_PARAM, i)) == -1)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
+
+               if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
+
+               if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
+
+               first_param = FALSE;
+               sequence = data [MONO_PARAM_SEQUENCE];
+               if (--remaining_params == 0) {
+                       remaining_params = get_next_param_count (ctx, &current_method);
+                       first_param = TRUE;
+               }
+       }
+}
+
+static void
+verify_interfaceimpl_table (VerifyContext *ctx)
+{
+       MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
+       guint32 data [MONO_INTERFACEIMPL_SIZE];
+       int i;
+
+       for (i = 0; i < table->rows; ++i) {
+               mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
+               if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
+
+               if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
+
+               if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
        }
 }
 
@@ -1166,6 +1464,12 @@ verify_tables_data (VerifyContext *ctx)
        verify_typedef_table (ctx);
        CHECK_ERROR ();
        verify_field_table (ctx);
+       CHECK_ERROR ();
+       verify_method_table (ctx);
+       CHECK_ERROR ();
+       verify_param_table (ctx);
+       CHECK_ERROR ();
+       verify_interfaceimpl_table (ctx);
 }
 
 static gboolean
@@ -1205,9 +1509,6 @@ mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
 {
        VerifyContext ctx;
 
-       /* a temporary workaround for bug #496453 */
-       return TRUE;
-
        if (!mono_verifier_is_enabled_for_image (image))
                return TRUE;