#include <mono/metadata/security-manager.h>
#include <mono/metadata/security-core-clr.h>
#include <mono/metadata/cil-coff.h>
+#include <mono/metadata/attrdefs.h>
#include <mono/utils/strenc.h>
#include <string.h>
-#include <signal.h>
+//#include <signal.h>
#include <ctype.h>
#ifndef DISABLE_VERIFIER
#define HAS_CATTR_DESC (HAS_CONSTANT_DESC + 5)
5, /*bits*/
- 19, /*tables*/
+ 20, /*tables*/
MONO_TABLE_METHOD,
MONO_TABLE_FIELD,
MONO_TABLE_TYPEREF,
MONO_TABLE_FILE,
MONO_TABLE_EXPORTEDTYPE,
MONO_TABLE_MANIFESTRESOURCE,
+ MONO_TABLE_GENERICPARAM,
-#define HAS_FIELD_MARSHAL_DESC (HAS_CATTR_DESC + 21)
+#define HAS_FIELD_MARSHAL_DESC (HAS_CATTR_DESC + 22)
1, /*bits*/
2, /*tables*/
MONO_TABLE_FIELD,
guint32 size;
GSList *errors;
int valid;
- gboolean is_corlib;
MonoImage *image;
gboolean report_error;
int stage;
return; \
} while (0)
+#define FAIL(__ctx, __msg) \
+ do { \
+ if ((__ctx)->report_error) \
+ ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
+ (__ctx)->valid = 0; \
+ return FALSE; \
+ } while (0)
+
#define CHECK_STATE() do { if (!ctx.valid) goto cleanup; } while (0)
#define CHECK_ERROR() do { if (!ctx->valid) return; } while (0)
+#define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
+#define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
+
+#if SIZEOF_VOID_P == 4
+#define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
+#else
+#define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
+#endif
+
+#define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
+#define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
+
+static const char *
+dword_align (const char *ptr)
+{
+#if SIZEOF_VOID_P == 8
+ return (const char *) (((guint64) (ptr + 3)) & ~3);
+#else
+ return (const char *) (((guint32) (ptr + 3)) & ~3);
+#endif
+}
+
static guint32
pe_signature_offset (VerifyContext *ctx)
{
ADD_ERROR (ctx, g_strdup_printf ("Import table size %d is smaller than 40", it.size));
ilt_rva = read32 (ptr);
- if (!bounds_check_virtual_address (ctx, ilt_rva, 8))
+ if (ilt_rva && !bounds_check_virtual_address (ctx, ilt_rva, 8))
ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Lookup Table rva %x", ilt_rva));
name_rva = read32 (ptr + 12);
- if (!bounds_check_virtual_address (ctx, name_rva, SIZE_OF_MSCOREE))
+ if (name_rva && !bounds_check_virtual_address (ctx, name_rva, SIZE_OF_MSCOREE))
ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name rva %x", name_rva));
iat_rva = read32 (ptr + 16);
- if (!bounds_check_virtual_address (ctx, iat_rva, 8))
- ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Address Table rva %x", iat_rva));
+ if (iat_rva) {
+ if (!bounds_check_virtual_address (ctx, iat_rva, 8))
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Address Table rva %x", iat_rva));
- if (iat_rva != ctx->data_directories [IAT_IDX].rva)
- ADD_ERROR (ctx, g_strdup_printf ("Import Address Table rva %x different from data directory entry %x", read32 (ptr + 16), ctx->data_directories [IAT_IDX].rva));
-
- name_rva = translate_rva (ctx, name_rva);
- g_assert (name_rva != INVALID_OFFSET);
- ptr = ctx->data + name_rva;
+ if (iat_rva != ctx->data_directories [IAT_IDX].rva)
+ ADD_ERROR (ctx, g_strdup_printf ("Import Address Table rva %x different from data directory entry %x", read32 (ptr + 16), ctx->data_directories [IAT_IDX].rva));
+ }
- if (memcmp ("mscoree.dll", ptr, SIZE_OF_MSCOREE)) {
- char name[SIZE_OF_MSCOREE];
- memcpy (name, ptr, SIZE_OF_MSCOREE);
- name [SIZE_OF_MSCOREE - 1] = 0;
- ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name: '%s'", name));
+ if (name_rva) {
+ name_rva = translate_rva (ctx, name_rva);
+ g_assert (name_rva != INVALID_OFFSET);
+ ptr = ctx->data + name_rva;
+
+ if (memcmp ("mscoree.dll", ptr, SIZE_OF_MSCOREE)) {
+ char name[SIZE_OF_MSCOREE];
+ memcpy (name, ptr, SIZE_OF_MSCOREE);
+ name [SIZE_OF_MSCOREE - 1] = 0;
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name: '%s'", name));
+ }
}
- verify_hint_name_table (ctx, ilt_rva, "Import Lookup Table");
- CHECK_ERROR ();
- verify_hint_name_table (ctx, iat_rva, "Import Address Table");
+ if (ilt_rva) {
+ verify_hint_name_table (ctx, ilt_rva, "Import Lookup Table");
+ CHECK_ERROR ();
+ }
+
+ if (iat_rva)
+ verify_hint_name_table (ctx, iat_rva, "Import Address Table");
}
static void
}
static gboolean
-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_or_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_vald_cattr_blob (VerifyContext *ctx, guint32 offset)
-{
- OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
- //TODO do proper verification
- return blob.size >= 1 && blob.size - 1 >= offset;
-}
-
-static gboolean
-is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
-{
- OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
- //TODO do proper verification
- return blob.size >= 1 && blob.size - 1 >= offset;
-}
-
-static gboolean
-is_valid_permission_set (VerifyContext *ctx, guint32 offset)
-{
- OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
- //TODO do proper verification
- return blob.size >= 1 && blob.size - 1 >= offset;
-}
-
-static gboolean
-is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
+mono_verifier_is_corlib (MonoImage *image)
{
- OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
- //TODO do proper verification
- return blob.size >= 1 && blob.size - 1 >= offset;
-}
+ gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ?
+ TRUE : mono_security_core_clr_is_platform_image (image);
-static gboolean
-is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
-{
- OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
- //TODO do proper verification
- return offset > 0 && blob.size >= 1 && blob.size - 1 >= offset;
+ return trusted_location && image->module_name && !strcmp ("mscorlib.dll", image->module_name);
}
static gboolean
-is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
+typedef_is_system_object (VerifyContext *ctx, guint32 *data)
{
- OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
- //TODO do proper verification
- return offset > 0 && blob.size >= 1 && blob.size - 1 >= offset;
+ return mono_verifier_is_corlib (ctx->image) && !string_cmp (ctx, "System", data [MONO_TYPEDEF_NAMESPACE]) && !string_cmp (ctx, "Object", data [MONO_TYPEDEF_NAME]);
}
static gboolean
-decode_value (const char *_ptr, guint32 available, guint32 *value, guint32 *size)
+decode_value (const char *_ptr, unsigned available, unsigned *value, unsigned *size)
{
unsigned char b;
const unsigned char *ptr = (const unsigned char *)_ptr;
}
static gboolean
-is_valid_blob_object (VerifyContext *ctx, guint32 offset)
+decode_signature_header (VerifyContext *ctx, guint32 offset, int *size, const char **first_byte)
{
- OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
- guint32 entry_size, bytes;
+ MonoStreamHeader blob = ctx->image->heap_blob;
+ guint32 value, enc_size;
- if (blob.size < offset) {
- printf ("1\n");
+ if (offset >= blob.size)
return FALSE;
- }
- if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
+ if (!decode_value (blob.data + offset, blob.size - offset, &value, &enc_size))
+ return FALSE;
+
+ if (offset + enc_size + value < offset)
return FALSE;
- if (offset + entry_size < offset)
+ if (offset + enc_size + value > blob.size)
return FALSE;
- return blob.size >= offset + entry_size;
+ *size = value;
+ *first_byte = blob.data + offset + enc_size;
+ return TRUE;
}
static gboolean
-is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
+safe_read (const char **_ptr, const char *limit, void *dest, int size)
{
- OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
- guint32 size, entry_size, bytes;
-
- if (blob.size < offset) {
- printf ("1\n");
- return FALSE;
- }
-
-
- if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
+ const char *ptr = *_ptr;
+ if (ptr + size > limit)
return FALSE;
-
- if (type == MONO_TYPE_STRING) {
- //String is encoded as: compressed_int:len len *chars
-
- offset += bytes;
- if (offset > offset + entry_size * 2) //overflow
- return FALSE;
- offset += offset + entry_size * 2;
- return offset <= blob.size;
- }
-
- switch (type) {
- case MONO_TYPE_BOOLEAN:
- case MONO_TYPE_I1:
- case MONO_TYPE_U1:
- size = 1;
- break;
- case MONO_TYPE_CHAR:
- case MONO_TYPE_I2:
- case MONO_TYPE_U2:
- size = 2;
+ switch (size) {
+ case 1:
+ *((guint8*)dest) = *((guint8*)ptr);
+ ++ptr;
break;
- case MONO_TYPE_I4:
- case MONO_TYPE_U4:
- case MONO_TYPE_R4:
- case MONO_TYPE_CLASS:
- size = 4;
+ case 2:
+ *((guint16*)dest) = read16 (ptr);
+ ptr += 2;
break;
-
- case MONO_TYPE_I8:
- case MONO_TYPE_U8:
- case MONO_TYPE_R8:
- size = 8;
+ case 4:
+ *((guint32*)dest) = read32 (ptr);
+ ptr += 4;
break;
- default:
- g_assert_not_reached ();
}
+ *_ptr = ptr;
+ return TRUE;
+}
- if (size != entry_size)
- return FALSE;
- offset += bytes;
+static gboolean
+safe_read_compressed_int (const char **_ptr, const char *limit, unsigned *dest)
+{
+ unsigned size = 0;
+ const char *ptr = *_ptr;
+ gboolean res = decode_value (ptr, limit - ptr, dest, &size);
+ *_ptr = ptr + size;
+ return res;
+}
- if(offset > offset + size) //overflow
- return FALSE;
+#define safe_read8(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 1)
+#define safe_read_cint(VAR, PTR, LIMIT) safe_read_compressed_int (&PTR, LIMIT, &VAR)
+#define safe_read16(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 2)
+#define safe_read32(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 4)
- if (offset + size > blob.size)
- return FALSE;
+static gboolean
+parse_type (VerifyContext *ctx, const char **_ptr, const char *end);
- if (type == MONO_TYPE_CLASS && read32 (ctx->data + offset))
- return FALSE;
- return TRUE;
-}
+static gboolean
+parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged);
static gboolean
-is_valid_method_header (VerifyContext *ctx, guint32 rva)
+parse_custom_mods (VerifyContext *ctx, const char **_ptr, const char *end)
{
- //TODO do proper method header validation
- return mono_cli_rva_image_map (ctx->image, rva) != INVALID_ADDRESS;
+ const char *ptr = *_ptr;
+ guint type = 0;
+ guint32 token = 0;
+
+ while (TRUE) {
+ if (!safe_read8 (type, ptr, end))
+ FAIL (ctx, g_strdup ("CustomMod: Not enough room for the type"));
+
+ if (type != MONO_TYPE_CMOD_REQD && type != MONO_TYPE_CMOD_OPT) {
+ --ptr;
+ break;
+ }
+
+ if (!safe_read_cint (token, ptr, end))
+ FAIL (ctx, g_strdup ("CustomMod: Not enough room for the token"));
+
+ if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
+ FAIL (ctx, g_strdup_printf ("CustomMod: invalid TypeDefOrRef token %x", token));
+ }
+
+ *_ptr = ptr;
+ return TRUE;
}
-static void
-verify_module_table (VerifyContext *ctx)
+static gboolean
+parse_array_shape (VerifyContext *ctx, const char **_ptr, const char *end)
{
- MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
- guint32 data [MONO_MODULE_SIZE];
+ const char *ptr = *_ptr;
+ guint8 val;
+ guint32 size, num, i;
- if (table->rows != 1)
- ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
+ if (!safe_read8 (val, ptr, end))
+ FAIL (ctx, g_strdup ("ArrayShape: Not enough room for Rank"));
- mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
+ if (val == 0)
+ FAIL (ctx, g_strdup ("ArrayShape: Invalid shape with zero Rank"));
- if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
- ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
+ if (!safe_read_cint (size, ptr, end))
+ FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumSizes"));
- if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
- ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
+ for (i = 0; i < size; ++i) {
+ if (!safe_read_cint (num, ptr, end))
+ FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for Size of rank %d", i + 1));
+ }
- if (data [MONO_MODULE_ENC] != 0)
- ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
+ if (!safe_read_cint (size, ptr, end))
+ FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumLoBounds"));
- if (data [MONO_MODULE_ENCBASE] != 0)
- ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
+ for (i = 0; i < size; ++i) {
+ if (!safe_read_cint (num, ptr, end))
+ FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for LoBound of rank %d", i + 1));
+ }
+
+ *_ptr = ptr;
+ return TRUE;
}
-static void
-verify_typeref_table (VerifyContext *ctx)
+static gboolean
+parse_generic_inst (VerifyContext *ctx, const char **_ptr, const char *end)
{
- MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
- guint32 data [MONO_TYPEREF_SIZE];
- int i;
+ const char *ptr = *_ptr;
+ guint8 type;
+ guint32 count, token, i;
- for (i = 0; i < table->rows; ++i) {
- mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
- 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 (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 (!safe_read8 (type, ptr, end))
+ FAIL (ctx, g_strdup ("GenericInst: Not enough room for kind"));
- if (!data [MONO_TYPEREF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAME]))
- ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d name token 0x%08x", i, data [MONO_TYPEREF_NAME]));
+ if (type != MONO_TYPE_CLASS && type != MONO_TYPE_VALUETYPE)
+ FAIL (ctx, g_strdup_printf ("GenericInst: Invalid GenericInst kind %x\n", type));
- if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
- ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d namespace token 0x%08x", i, data [MONO_TYPEREF_NAMESPACE]));
+ if (!safe_read_cint (token, ptr, end))
+ FAIL (ctx, g_strdup ("GenericInst: Not enough room for type token"));
+
+ if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
+ FAIL (ctx, g_strdup_printf ("GenericInst: invalid TypeDefOrRef token %x", token));
+
+ if (!safe_read_cint (count, ptr, end))
+ FAIL (ctx, g_strdup ("GenericInst: Not enough room for argument count"));
+
+ if (count == 0)
+ FAIL (ctx, g_strdup ("GenericInst: Zero arguments generic instance"));
+
+ for (i = 0; i < count; ++i) {
+ if (!parse_type (ctx, &ptr, end))
+ FAIL (ctx, g_strdup_printf ("GenericInst: invalid generic argument %d", i + 1));
}
+ *_ptr = ptr;
+ return TRUE;
}
-/*bits 9,11,14,15,19,21,24-31 */
-#define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 14) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
-static void
-verify_typedef_table (VerifyContext *ctx)
+static gboolean
+parse_type (VerifyContext *ctx, const char **_ptr, const char *end)
{
- MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
- guint32 data [MONO_TYPEDEF_SIZE];
- guint32 fieldlist = 1, methodlist = 1;
- int i;
-
- if (table->rows == 0)
- ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
-
- for (i = 0; i < table->rows; ++i) {
- mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
- if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
- ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
+ const char *ptr = *_ptr;
+ guint8 type = 0;
+ guint32 token = 0;
- if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
- ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
+ if (!safe_read8 (type, ptr, end))
+ FAIL (ctx, g_strdup ("Type: Not enough room for the type"));
- if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
- ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
+ if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_PTR) ||
+ (type >= MONO_TYPE_VALUETYPE && type <= MONO_TYPE_GENERICINST) ||
+ (type >= MONO_TYPE_I && type <= MONO_TYPE_U) ||
+ (type >= MONO_TYPE_FNPTR && type <= MONO_TYPE_MVAR)))
+ FAIL (ctx, g_strdup_printf ("Type: Invalid type kind %x\n", type));
- if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
- ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
+ switch (type) {
+ case MONO_TYPE_PTR:
+ if (!parse_custom_mods (ctx, &ptr, end))
+ FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
- if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
- ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
+ if (!safe_read8 (type, ptr, end))
+ FAIL (ctx, g_strdup ("Type: Not enough room to parse the pointer type"));
- if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
- ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
+ if (type != MONO_TYPE_VOID) {
+ --ptr;
+ if (!parse_type (ctx, &ptr, end))
+ FAIL (ctx, g_strdup ("Type: Could not parse pointer type"));
+ }
+ break;
- if (i == 0) {
- if (data [MONO_TYPEDEF_EXTENDS] != 0)
- ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
- } else {
- if (typedef_is_system_object (ctx, data) && data [MONO_TYPEDEF_EXTENDS] != 0)
- ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
-
- if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
- if (data [MONO_TYPEDEF_EXTENDS])
- ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
- if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
- ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
- } else {
- 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]));
+ case MONO_TYPE_VALUETYPE:
+ case MONO_TYPE_CLASS:
+ if (!safe_read_cint (token, ptr, end))
+ FAIL (ctx, g_strdup ("Type: Not enough room for the type token"));
- 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));
- }
- }
+ if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
+ FAIL (ctx, g_strdup_printf ("Type: invalid TypeDefOrRef token %x", token));
+ break;
- if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
- ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
+ case MONO_TYPE_VAR:
+ case MONO_TYPE_MVAR:
+ if (!safe_read_cint (token, ptr, end))
+ FAIL (ctx, g_strdup ("Type: Not enough room for to decode generic argument number"));
+ break;
- 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]));
+ case MONO_TYPE_ARRAY:
+ if (!parse_type (ctx, &ptr, end))
+ FAIL (ctx, g_strdup ("Type: Could not parse array type"));
+ if (!parse_array_shape (ctx, &ptr, end))
+ FAIL (ctx, g_strdup ("Type: Could not parse array shape"));
+ break;
- 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));
+ case MONO_TYPE_GENERICINST:
+ if (!parse_generic_inst (ctx, &ptr, end))
+ FAIL (ctx, g_strdup ("Type: Could not parse generic inst"));
+ break;
- if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
- ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
+ case MONO_TYPE_FNPTR:
+ if (!parse_method_signature (ctx, &ptr, end, TRUE, TRUE))
+ FAIL (ctx, g_strdup ("Type: Could not parse method pointer signature"));
+ break;
+
+ case MONO_TYPE_SZARRAY:
+ if (!parse_custom_mods (ctx, &ptr, end))
+ FAIL (ctx, g_strdup ("Type: Failed to parse array element custom attr"));
+ if (!parse_type (ctx, &ptr, end))
+ FAIL (ctx, g_strdup ("Type: Could not parse array type"));
+ break;
+ }
+ *_ptr = ptr;
+ return TRUE;
+}
+
+static gboolean
+parse_return_type (VerifyContext *ctx, const char **_ptr, const char *end)
+{
+ const char *ptr;
+ int type = 0;
+
+ if (!parse_custom_mods (ctx, _ptr, end))
+ return FALSE;
+
+ ptr = *_ptr;
+ if (!safe_read8 (type, ptr, end))
+ FAIL (ctx, g_strdup ("ReturnType: Not enough room for the type"));
+
+ if (type == MONO_TYPE_VOID || type == MONO_TYPE_TYPEDBYREF) {
+ *_ptr = ptr;
+ return TRUE;
+ }
+
+ //it's a byref, update the cursor ptr
+ if (type == MONO_TYPE_BYREF)
+ *_ptr = ptr;
+
+ return parse_type (ctx, _ptr, end);
+}
+
+static gboolean
+parse_param (VerifyContext *ctx, const char **_ptr, const char *end)
+{
+ const char *ptr;
+ int type = 0;
+
+ if (!parse_custom_mods (ctx, _ptr, end))
+ return FALSE;
+
+ ptr = *_ptr;
+ if (!safe_read8 (type, ptr, end))
+ FAIL (ctx, g_strdup ("Param: Not enough room for the type"));
+
+ if (type == MONO_TYPE_TYPEDBYREF) {
+ *_ptr = ptr;
+ return TRUE;
+ }
+
+ //it's a byref, update the cursor ptr
+ if (type == MONO_TYPE_BYREF)
+ *_ptr = ptr;
+
+ return parse_type (ctx, _ptr, end);
+}
+
+static gboolean
+parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged)
+{
+ int cconv = 0;
+ unsigned param_count = 0, gparam_count = 0, type = 0, i;
+ const char *ptr = *_ptr;
+ gboolean saw_sentinel = FALSE;
+
+ if (!safe_read8 (cconv, ptr, end))
+ FAIL (ctx, g_strdup ("MethodSig: Not enough room for the call conv"));
+
+ if (cconv & 0x80)
+ FAIL (ctx, g_strdup ("MethodSig: CallConv has 0x80 set"));
+
+ if (allow_unmanaged) {
+ if ((cconv & 0x0F) > MONO_CALL_VARARG)
+ FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not valid, it's %x", cconv & 0x0F));
+ } else if ((cconv & 0x0F) != MONO_CALL_DEFAULT && (cconv & 0x0F) != MONO_CALL_VARARG)
+ FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not Default or Vararg, it's %x", cconv & 0x0F));
+
+ if ((cconv & 0x10) && !safe_read_cint (gparam_count, ptr, end))
+ FAIL (ctx, g_strdup ("MethodSig: Not enough room for the generic param count"));
+
+ if ((cconv & 0x10) && gparam_count == 0)
+ FAIL (ctx, g_strdup ("MethodSig: Signature with generics but zero arity"));
+
+ if (allow_unmanaged && (cconv & 0x10))
+ FAIL (ctx, g_strdup ("MethodSig: Standalone signature with generic params"));
+
+ if (!safe_read_cint (param_count, ptr, end))
+ FAIL (ctx, g_strdup ("MethodSig: Not enough room for the param count"));
+
+ if (!parse_return_type (ctx, &ptr, end))
+ FAIL (ctx, g_strdup ("MethodSig: Error parsing return type"));
+
+ for (i = 0; i < param_count; ++i) {
+ if (allow_sentinel) {
+ if (!safe_read8 (type, ptr, end))
+ FAIL (ctx, g_strdup_printf ("MethodSig: Not enough room for param %d type", i));
+
+ if (type == MONO_TYPE_SENTINEL) {
+ if ((cconv & 0x0F) != MONO_CALL_VARARG)
+ FAIL (ctx, g_strdup ("MethodSig: Found sentinel but signature is not vararg"));
+
+ if (saw_sentinel)
+ FAIL (ctx, g_strdup ("MethodSig: More than one sentinel type"));
+
+ saw_sentinel = TRUE;
+ } else {
+ --ptr;
+ }
+ }
+
+ if (!parse_param (ctx, &ptr, end))
+ FAIL (ctx, g_strdup_printf ("MethodSig: Error parsing arg %d", i));
+ }
+
+ *_ptr = ptr;
+ return TRUE;
+}
+
+static gboolean
+parse_property_signature (VerifyContext *ctx, const char **_ptr, const char *end)
+{
+ unsigned sig = 0;
+ unsigned param_count = 0, i;
+ const char *ptr = *_ptr;
+
+ if (!safe_read8 (sig, ptr, end))
+ FAIL (ctx, g_strdup ("PropertySig: Not enough room for signature"));
+
+ if (sig != 0x08 && sig != 0x28)
+ FAIL (ctx, g_strdup_printf ("PropertySig: Signature is not 0x28 or 0x08: %x", sig));
+
+ if (!safe_read_cint (param_count, ptr, end))
+ FAIL (ctx, g_strdup ("PropertySig: Not enough room for the param count"));
+
+ if (!parse_custom_mods (ctx, &ptr, end))
+ return FALSE;
+
+ if (!parse_type (ctx, &ptr, end))
+ FAIL (ctx, g_strdup ("PropertySig: Could not parse property type"));
+
+ for (i = 0; i < param_count; ++i) {
+ if (!parse_type (ctx, &ptr, end))
+ FAIL (ctx, g_strdup_printf ("PropertySig: Error parsing arg %d", i));
+ }
+
+ *_ptr = ptr;
+ return TRUE;
+}
+
+static gboolean
+parse_field (VerifyContext *ctx, const char **_ptr, const char *end)
+{
+ const char *ptr = *_ptr;
+ guint8 signature = 0;
+
+ if (!safe_read8 (signature, ptr, end))
+ FAIL (ctx, g_strdup ("Field: Not enough room for field signature"));
+
+ if (signature != 0x06)
+ FAIL (ctx, g_strdup_printf ("Field: Invalid signature 0x%x, must be 6", signature));
+
+ if (!parse_custom_mods (ctx, &ptr, end))
+ return FALSE;
+
+ if (safe_read8 (signature, ptr, end)) {
+ if (signature != MONO_TYPE_BYREF)
+ --ptr;
+ }
+ *_ptr = ptr;
+
+ return parse_type (ctx, _ptr, end);
+}
+
+static gboolean
+parse_locals_signature (VerifyContext *ctx, const char **_ptr, const char *end)
+{
+ unsigned sig = 0;
+ unsigned locals_count = 0, i;
+ const char *ptr = *_ptr;
+
+ if (!safe_read8 (sig, ptr, end))
+ FAIL (ctx, g_strdup ("LocalsSig: Not enough room for signature"));
+
+ if (sig != 0x07)
+ FAIL (ctx, g_strdup_printf ("LocalsSig: Signature is not 0x28 or 0x08: %x", sig));
+
+ if (!safe_read_cint (locals_count, ptr, end))
+ FAIL (ctx, g_strdup ("LocalsSig: Not enough room for the param count"));
+
+ /* LAMEIMPL: MS sometimes generates empty local signatures and its verifier is ok with.
+ if (locals_count == 0)
+ FAIL (ctx, g_strdup ("LocalsSig: Signature with zero locals"));
+ */
+
+ for (i = 0; i < locals_count; ++i) {
+ if (!safe_read8 (sig, ptr, end))
+ FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
+
+ while (sig == MONO_TYPE_CMOD_REQD || sig == MONO_TYPE_CMOD_OPT || sig == MONO_TYPE_PINNED) {
+ if (sig != MONO_TYPE_PINNED && !parse_custom_mods (ctx, &ptr, end))
+ FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
+ if (!safe_read8 (sig, ptr, end))
+ FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
+ }
+
+ if (sig == MONO_TYPE_BYREF) {
+ if (!safe_read8 (sig, ptr, end))
+ FAIL (ctx, g_strdup_printf ("Type: Not enough room for byref type for local %d", i));
+ if (sig == MONO_TYPE_TYPEDBYREF)
+ FAIL (ctx, g_strdup_printf ("Type: Invalid type typedref& for local %d", i));
+ }
+
+ if (sig == MONO_TYPE_TYPEDBYREF)
+ continue;
+
+ --ptr;
+
+ if (!parse_type (ctx, &ptr, end))
+ FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
+ }
+
+ *_ptr = ptr;
+ return TRUE;
+}
+
+static gboolean
+is_valid_field_signature (VerifyContext *ctx, guint32 offset)
+{
+ int size = 0, signature = 0;
+ const char *ptr = NULL, *end;
+
+ if (!decode_signature_header (ctx, offset, &size, &ptr))
+ FAIL (ctx, g_strdup ("FieldSig: Could not decode signature header"));
+ end = ptr + size;
+
+ if (!safe_read8 (signature, ptr, end))
+ FAIL (ctx, g_strdup ("FieldSig: Not enough room for the signature"));
+
+ if (signature != 6)
+ FAIL (ctx, g_strdup_printf ("FieldSig: Invalid signature %x", signature));
+ --ptr;
+
+ return parse_field (ctx, &ptr, end);
+}
+
+static gboolean
+is_valid_method_signature (VerifyContext *ctx, guint32 offset)
+{
+ int size = 0;
+ const char *ptr = NULL, *end;
+
+ if (!decode_signature_header (ctx, offset, &size, &ptr))
+ FAIL (ctx, g_strdup ("MethodSig: Could not decode signature header"));
+ end = ptr + size;
+
+ return parse_method_signature (ctx, &ptr, end, FALSE, FALSE);
+}
+
+static gboolean
+is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
+{
+ int size = 0;
+ unsigned signature = 0;
+ const char *ptr = NULL, *end;
+
+ if (!decode_signature_header (ctx, offset, &size, &ptr))
+ FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
+ end = ptr + size;
+
+ if (!safe_read8 (signature, ptr, end))
+ FAIL (ctx, g_strdup ("MemberRefSig: Not enough room for the call conv"));
+ --ptr;
+
+ if (signature == 0x06)
+ return parse_field (ctx, &ptr, end);
+
+ return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
+}
+
+static gboolean
+is_vald_cattr_blob (VerifyContext *ctx, guint32 offset)
+{
+ int size = 0;
+ guint16 prolog = 0;
+ const char *ptr = NULL, *end;
+
+ if (!offset)
+ return TRUE;
+
+ if (!decode_signature_header (ctx, offset, &size, &ptr))
+ FAIL (ctx, g_strdup ("CustomAttribute: Could not decode signature header"));
+ end = ptr + size;
+
+ if (!safe_read16 (prolog, ptr, end))
+ FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
+
+ if (prolog != 1)
+ FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
+
+ return TRUE;
+}
+
+static gboolean
+is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
+{
+ OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
+ //TODO do proper verification
+ return blob.size >= 1 && blob.size - 1 >= offset;
+}
+
+static gboolean
+is_valid_permission_set (VerifyContext *ctx, guint32 offset)
+{
+ OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
+ //TODO do proper verification
+ return blob.size >= 1 && blob.size - 1 >= offset;
+}
+
+static gboolean
+is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
+{
+ int size = 0;
+ unsigned signature = 0;
+ const char *ptr = NULL, *end;
+
+ if (!decode_signature_header (ctx, offset, &size, &ptr))
+ FAIL (ctx, g_strdup ("StandAloneSig: Could not decode signature header"));
+ end = ptr + size;
+
+ if (!safe_read8 (signature, ptr, end))
+ FAIL (ctx, g_strdup ("StandAloneSig: Not enough room for the call conv"));
+
+ --ptr;
+ if (signature == 0x07)
+ return parse_locals_signature (ctx, &ptr, end);
+ return parse_method_signature (ctx, &ptr, end, TRUE, TRUE);
+}
+
+static gboolean
+is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
+{
+ int size = 0;
+ const char *ptr = NULL, *end;
+
+ if (!decode_signature_header (ctx, offset, &size, &ptr))
+ FAIL (ctx, g_strdup ("PropertySig: Could not decode signature header"));
+ end = ptr + size;
+
+ return parse_property_signature (ctx, &ptr, end);
+}
+
+static gboolean
+is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
+{
+ int size = 0;
+ const char *ptr = NULL, *end;
+ guint8 type = 0;
+
+
+ if (!decode_signature_header (ctx, offset, &size, &ptr))
+ FAIL (ctx, g_strdup ("TypeSpec: Could not decode signature header"));
+ end = ptr + size;
+
+ if (!parse_custom_mods (ctx, &ptr, end))
+ return FALSE;
+
+ if (!safe_read8 (type, ptr, end))
+ FAIL (ctx, g_strdup ("TypeSpec: Not enough room for type"));
+
+ if (type == MONO_TYPE_BYREF) {
+ if (!safe_read8 (type, ptr, end))
+ FAIL (ctx, g_strdup ("TypeSpec: Not enough room for byref type"));
+ if (type == MONO_TYPE_TYPEDBYREF)
+ FAIL (ctx, g_strdup ("TypeSpec: Invalid type typedref&"));
+ }
+
+ if (type == MONO_TYPE_TYPEDBYREF)
+ return TRUE;
+
+ --ptr;
+ return parse_type (ctx, &ptr, end);
+}
+
+static gboolean
+is_valid_methodspec_blog (VerifyContext *ctx, guint32 offset)
+{
+ int size = 0;
+ const char *ptr = NULL, *end;
+ guint8 type = 0;
+ guint32 count = 0, i;
+
+ if (!decode_signature_header (ctx, offset, &size, &ptr))
+ FAIL (ctx, g_strdup ("MethodSpec: Could not decode signature header"));
+ end = ptr + size;
+
+ if (!safe_read8 (type, ptr, end))
+ FAIL (ctx, g_strdup ("MethodSpec: Not enough room for call convention"));
+
+ if (type != 0x0A)
+ FAIL (ctx, g_strdup_printf ("MethodSpec: Invalid call convention 0x%x, expected 0x0A", type));
+
+ if (!safe_read_cint (count, ptr, end))
+ FAIL (ctx, g_strdup ("MethodSpec: Not enough room for parameter count"));
+
+ if (!count)
+ FAIL (ctx, g_strdup ("MethodSpec: Zero generic argument count"));
+
+ for (i = 0; i < count; ++i) {
+ if (!parse_type (ctx, &ptr, end))
+ FAIL (ctx, g_strdup_printf ("MethodSpec: Could not parse parameter %d", i + 1));
+ }
+ return TRUE;
+}
+
+static gboolean
+is_valid_blob_object (VerifyContext *ctx, guint32 offset, guint32 minsize)
+{
+ OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
+ guint32 entry_size, bytes;
+
+ if (blob.size < offset)
+ return FALSE;
+
+ if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
+ return FALSE;
+
+ if (entry_size < minsize)
+ return FALSE;
+
+ if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
+ return FALSE;
+ entry_size += bytes;
+
+ return !ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size);
+}
+
+static gboolean
+is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
+{
+ OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
+ guint32 size, entry_size, bytes;
+
+ if (blob.size < offset)
+ FAIL (ctx, g_strdup ("ContantValue: invalid offset"));
+
+ if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
+ FAIL (ctx, g_strdup ("ContantValue: not enough space to decode size"));
+
+ if (type == MONO_TYPE_STRING) {
+ //String is encoded as: compressed_int:len len *bytes
+ offset += bytes;
+
+ if (ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size))
+ FAIL (ctx, g_strdup_printf ("ContantValue: not enough space for string, required %d but got %d", entry_size * 2, blob.size - offset));
+
+ return TRUE;
+ }
+
+ switch (type) {
+ case MONO_TYPE_BOOLEAN:
+ case MONO_TYPE_I1:
+ case MONO_TYPE_U1:
+ size = 1;
+ break;
+ case MONO_TYPE_CHAR:
+ case MONO_TYPE_I2:
+ case MONO_TYPE_U2:
+ size = 2;
+ break;
+ case MONO_TYPE_I4:
+ case MONO_TYPE_U4:
+ case MONO_TYPE_R4:
+ case MONO_TYPE_CLASS:
+ size = 4;
+ break;
+
+ case MONO_TYPE_I8:
+ case MONO_TYPE_U8:
+ case MONO_TYPE_R8:
+ size = 8;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ if (size != entry_size)
+ FAIL (ctx, g_strdup_printf ("ContantValue: Expected size %d but got %d", size, entry_size));
+
+ offset += bytes;
+
+ if (ADD_IS_GREATER_OR_OVF (offset, size, blob.size))
+ FAIL (ctx, g_strdup_printf ("ContantValue: Not enough room for constant, required %d but have %d", size, blob.size - offset));
+
+ if (type == MONO_TYPE_CLASS && read32 (ctx->data + blob.offset + offset))
+ FAIL (ctx, g_strdup_printf ("ContantValue: Type is class but value is not null"));
+ return TRUE;
+}
+
+#define FAT_HEADER_INVALID_FLAGS ~(0x3 | 0x8 | 0x10 | 0xF000)
+//only 0x01, 0x40 and 0x80 are allowed
+#define SECTION_HEADER_INVALID_FLAGS 0x3E
+
+static gboolean
+is_valid_method_header (VerifyContext *ctx, guint32 rva)
+{
+ guint32 local_vars_tok, code_size, offset = mono_cli_rva_image_map (ctx->image, rva);
+ guint8 header = 0;
+ guint16 fat_header = 0, size = 0, max_stack;
+ const char *ptr = NULL, *end;
+
+ if (offset == INVALID_ADDRESS)
+ FAIL (ctx, g_strdup ("MethodHeader: Invalid RVA"));
+
+ ptr = ctx->data + offset;
+ end = ctx->data + ctx->size; /*no worries if it spawns multiple sections*/
+
+ if (!safe_read8 (header, ptr, end))
+ FAIL (ctx, g_strdup ("MethodHeader: Not enough room for header"));
+
+ switch (header & 0x3) {
+ case 0:
+ case 1:
+ FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid header type 0x%x", header & 0x3));
+ case 2:
+ header >>= 2;
+ if (ADDP_IS_GREATER_OR_OVF (ptr, header, end))
+ FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for method body. Required %d, but only %d is available", header, (int)(end - ptr)));
+ return TRUE;
+ }
+ //FAT HEADER
+ --ptr;
+ if (!safe_read16 (fat_header, ptr, end))
+ FAIL (ctx, g_strdup ("MethodHeader: Not enough room for fat header"));
+
+ size = (fat_header >> 12) & 0xF;
+ if (size != 3)
+ FAIL (ctx, g_strdup ("MethodHeader: header size must be 3"));
+
+ if (!safe_read16 (max_stack, ptr, end))
+ FAIL (ctx, g_strdup ("MethodHeader: Not enough room for max stack"));
+
+ if (!safe_read32 (code_size, ptr, end))
+ FAIL (ctx, g_strdup ("MethodHeader: Not enough room for code size"));
+
+ if (!safe_read32 (local_vars_tok, ptr, end))
+ FAIL (ctx, g_strdup ("MethodHeader: Not enough room for local vars tok"));
+
+ if (local_vars_tok) {
+ if (((local_vars_tok >> 24) & 0xFF) != 0x11)
+ FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature table 0x%x", ((local_vars_tok >> 24) & 0xFF)));
+ if ((local_vars_tok & 0xFFFFFF) > ctx->image->tables [MONO_TABLE_STANDALONESIG].rows)
+ FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature points to invalid row 0x%x", local_vars_tok & 0xFFFFFF));
+ }
+
+ if (fat_header & FAT_HEADER_INVALID_FLAGS)
+ FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid fat signature flags %x", fat_header & FAT_HEADER_INVALID_FLAGS));
+
+ if (ADDP_IS_GREATER_OR_OVF (ptr, code_size, end))
+ FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for code %d", code_size));
+
+ if (!(fat_header & 0x08))
+ return TRUE;
+
+ ptr += code_size;
+
+ do {
+ guint32 section_header = 0, section_size = 0;
+ gboolean is_fat;
+
+ ptr = dword_align (ptr);
+ if (!safe_read32 (section_header, ptr, end))
+ FAIL (ctx, g_strdup ("MethodHeader: Not enough room for data section header"));
+
+ if (section_header & SECTION_HEADER_INVALID_FLAGS)
+ FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section header flags 0x%x", section_header & SECTION_HEADER_INVALID_FLAGS));
+
+ is_fat = (section_header & METHOD_HEADER_SECTION_FAT_FORMAT) != 0;
+ section_size = (section_header >> 8) & (is_fat ? 0xFFFFFF : 0xFF);
+
+ if (section_size < 4)
+ FAIL (ctx, g_strdup_printf ("MethodHeader: Section size too small"));
+
+ if (ADDP_IS_GREATER_OR_OVF (ptr, section_size - 4, end)) /*must be section_size -4 as ptr was incremented by safe_read32*/
+ FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section content %d", section_size));
+
+ if (section_header & METHOD_HEADER_SECTION_EHTABLE) {
+ guint32 i, clauses = (section_size - 4) / (is_fat ? 24 : 12);
+ if (clauses * (is_fat ? 24 : 12) + 4 != section_size)
+ FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid EH section size %d, it's not of the proper size", section_size));
+
+ /* only verify the class token is verified as the rest is done by the IL verifier*/
+ for (i = 0; i < clauses; ++i) {
+ guint flags = *ptr;
+ guint32 class_token = 0;
+ ptr += (is_fat ? 20 : 8);
+ if (!safe_read32 (class_token, ptr, end))
+ FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section %d", i));
+ if (flags == MONO_EXCEPTION_CLAUSE_NONE && class_token) {
+ guint table = mono_metadata_token_table (class_token);
+ if (table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPESPEC)
+ FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token table %x", i, table));
+ if (mono_metadata_token_index (class_token) > ctx->image->tables [table].rows)
+ FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token index %x", i, mono_metadata_token_index (class_token)));
+ }
+ }
+ }
+
+ if (!(section_header & METHOD_HEADER_SECTION_MORE_SECTS))
+ break;
+ } while (1);
+ return TRUE;
+}
+
+static void
+verify_module_table (VerifyContext *ctx)
+{
+ MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
+ guint32 data [MONO_MODULE_SIZE];
+
+ if (table->rows != 1)
+ ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
+
+ mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
+
+ if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
+ ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
+
+ if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
+ ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
+
+ if (data [MONO_MODULE_ENC] != 0)
+ ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
+
+ if (data [MONO_MODULE_ENCBASE] != 0)
+ ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
+}
+
+static void
+verify_typeref_table (VerifyContext *ctx)
+{
+ MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
+ guint32 data [MONO_TYPEREF_SIZE];
+ int i;
+
+ for (i = 0; i < table->rows; ++i) {
+ mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
+ 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 (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]))
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d name token 0x%08x", i, data [MONO_TYPEREF_NAME]));
+
+ if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d namespace token 0x%08x", i, data [MONO_TYPEREF_NAMESPACE]));
+ }
+}
+
+/*bits 9,11,14,15,19,21,24-31 */
+#define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 14) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
+static void
+verify_typedef_table (VerifyContext *ctx)
+{
+ MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
+ guint32 data [MONO_TYPEDEF_SIZE];
+ guint32 fieldlist = 1, methodlist = 1;
+ int i;
+
+ if (table->rows == 0)
+ ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
+
+ for (i = 0; i < table->rows; ++i) {
+ mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
+ if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
+
+ if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
+
+ if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
+
+ if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
+
+ if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) && (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
+
+ if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
+
+ if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
+
+ if (data [MONO_TYPEDEF_EXTENDS] && !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 (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];
}
}
+static void
+verify_typedef_table_full (VerifyContext *ctx)
+{
+ MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
+ guint32 data [MONO_TYPEDEF_SIZE];
+ int i;
+
+ if (table->rows == 0)
+ ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
+
+ for (i = 0; i < table->rows; ++i) {
+ mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
+
+ if (i == 0) {
+ if (data [MONO_TYPEDEF_EXTENDS] != 0)
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
+ continue;
+ }
+
+ if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
+ if (data [MONO_TYPEDEF_EXTENDS])
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
+ } else {
+ gboolean is_sys_obj = typedef_is_system_object (ctx, data);
+ gboolean has_parent = get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]) != 0;
+
+ if (is_sys_obj) {
+ if (has_parent)
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
+ } else {
+ if (!has_parent) {
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
+ }
+ }
+ }
+ }
+}
+
/*bits 3,11,14 */
#define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
static void
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]));
+ if (data [MONO_FIELD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_FIELD_SIGNATURE], 1))
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature blob token 0x%x", i, data [MONO_FIELD_SIGNATURE]));
+
//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;
}
}
+static void
+verify_field_table_full (VerifyContext *ctx)
+{
+ MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
+ guint32 data [MONO_FIELD_SIZE];
+ int i;
+
+ for (i = 0; i < table->rows; ++i) {
+ mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
+
+ 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]));
+ }
+}
+
/*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
//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));
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 ((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_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHOD_SIGNATURE], 1))
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature blob token 0x%x", i, data [MONO_METHOD_SIGNATURE]));
+
if (data [MONO_METHOD_PARAMLIST] == 0)
ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
}
}
+static void
+verify_method_table_full (VerifyContext *ctx)
+{
+ MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
+ guint32 data [MONO_METHOD_SIZE], rva;
+ int i;
+
+ for (i = 0; i < table->rows; ++i) {
+ mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
+ rva = data [MONO_METHOD_RVA];
+
+ 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 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
+
+ if (rva && !is_valid_method_header (ctx, rva))
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
+ }
+}
+
static guint32
get_next_param_count (VerifyContext *ctx, guint32 *current_method)
{
gboolean first_param = TRUE;
int i;
+ if (ctx->image->tables [MONO_TABLE_METHOD].rows == 0) {
+ if (table->rows > 0)
+ ADD_ERROR (ctx, g_strdup ("Param table has rows while the method table has zero"));
+ return;
+ }
+
remaining_params = get_next_param_count (ctx, ¤t_method);
for (i = 0; i < table->rows; ++i) {
if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
+ if (data [MONO_MEMBERREF_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_MEMBERREF_SIGNATURE], 1))
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d invalid signature blob token 0x%x", i, data [MONO_MEMBERREF_SIGNATURE]));
+ }
+}
+
+
+static void
+verify_memberref_table_full (VerifyContext *ctx)
+{
+ MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
+ guint32 data [MONO_MEMBERREF_SIZE];
+ int i;
+
+ for (i = 0; i < table->rows; ++i) {
+ mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
+
if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field 0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
}
if (!is_valid_coded_index (ctx, CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]))
ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
+ if (data [MONO_CUSTOM_ATTR_VALUE] && !is_valid_blob_object (ctx, data [MONO_CUSTOM_ATTR_VALUE], 0))
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d invalid value blob 0x%x", i, data [MONO_CUSTOM_ATTR_VALUE]));
+ }
+}
+
+static void
+verify_cattr_table_full (VerifyContext *ctx)
+{
+ MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
+ guint32 data [MONO_CUSTOM_ATTR_SIZE];
+ int i;
+
+ for (i = 0; i < table->rows; ++i) {
+ mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
+
if (!is_vald_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
-
}
}
if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
+ if (!is_valid_blob_object (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE], 1))
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d invalid NativeType blob 0x%x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
+ }
+}
+
+static void
+verify_field_marshal_table_full (VerifyContext *ctx)
+{
+ MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
+ guint32 data [MONO_FIELD_MARSHAL_SIZE];
+ int i;
+
+ for (i = 0; i < table->rows; ++i) {
+ mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
+
if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
-
}
}
if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
+ }
+}
+
+static void
+verify_decl_security_table_full (VerifyContext *ctx)
+{
+ MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
+ guint32 data [MONO_DECL_SECURITY_SIZE];
+ int i;
+
+ for (i = 0; i < table->rows; ++i) {
+ mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
-
}
}
guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
int i;
+ for (i = 0; i < table->rows; ++i) {
+ mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
+
+ if (data [MONO_STAND_ALONE_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_STAND_ALONE_SIGNATURE], 1))
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d invalid signature 0x%x", i, data [MONO_STAND_ALONE_SIGNATURE]));
+ }
+}
+
+static void
+verify_standalonesig_table_full (VerifyContext *ctx)
+{
+ MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
+ guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
+ int i;
+
for (i = 0; i < table->rows; ++i) {
mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
verify_event_table (VerifyContext *ctx)
{
MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
- MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
- guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
- gboolean found_add, found_remove;
- int i, idx;
+ guint32 data [MONO_EVENT_SIZE];
+ int i;
for (i = 0; i < table->rows; ++i) {
mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
+ }
+}
+
+static void
+verify_event_table_full (VerifyContext *ctx)
+{
+ MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
+ MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
+ guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
+ gboolean found_add, found_remove;
+ int i, idx;
+
+ for (i = 0; i < table->rows; ++i) {
+ mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
- //check for Add and Remove
token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
if (idx == -1)
guint32 data [MONO_TYPESPEC_SIZE];
int i;
+ for (i = 0; i < table->rows; ++i) {
+ mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
+
+ if (data [MONO_TYPESPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_TYPESPEC_SIGNATURE], 1))
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
+ }
+}
+
+static void
+verify_typespec_table_full (VerifyContext *ctx)
+{
+ MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
+ guint32 data [MONO_TYPESPEC_SIZE];
+ int i;
+
for (i = 0; i < table->rows; ++i) {
mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
}
}
-#define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10))
+#define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 6) | (1 << 8) | (1 << 9) | (1 << 10))
static void
verify_implmap_table (VerifyContext *ctx)
{
if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
- if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULE].rows + 1)
+ if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULEREF].rows + 1)
ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
}
}
if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
- if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY]))
+ if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY], 1))
ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
- if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY]))
+ if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY], 1))
ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
- if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE]))
+ if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE], 1))
ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
}
}
if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
- if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE]))
+ if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE], 1))
ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
}
}
}
}
+#define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
+static void
+verify_generic_param_table (VerifyContext *ctx)
+{
+ MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
+ guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
+ int i, param_number = 0;
+
+ for (i = 0; i < table->rows; ++i) {
+ mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
+
+ if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
+ ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
+
+ if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
+ ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
+
+ if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
+ ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
+
+ token = data [MONO_GENERICPARAM_OWNER];
+
+ if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
+ ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
+
+ if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
+ ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
+
+ if (token != last_token) {
+ param_number = 0;
+ last_token = token;
+ }
+
+ if (data [MONO_GENERICPARAM_NUMBER] != param_number)
+ ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d Number is out of order %d expected %d", i, data [MONO_GENERICPARAM_NUMBER], param_number));
+
+ ++param_number;
+ }
+}
+
+static void
+verify_method_spec_table (VerifyContext *ctx)
+{
+ MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
+ guint32 data [MONO_METHODSPEC_SIZE];
+ int i;
+
+ for (i = 0; i < table->rows; ++i) {
+ mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
+
+ if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
+ ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
+
+ if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
+ ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
+
+ if (data [MONO_METHODSPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHODSPEC_SIGNATURE], 1))
+ ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid signature token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
+ }
+}
+
+static void
+verify_method_spec_table_full (VerifyContext *ctx)
+{
+ MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
+ guint32 data [MONO_METHODSPEC_SIZE];
+ int i;
+
+ 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]))
+ ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
+ }
+}
+
+static void
+verify_generic_param_constraint_table (VerifyContext *ctx)
+{
+ MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
+ guint32 data [MONO_GENPARCONSTRAINT_SIZE];
+ int i;
+
+ for (i = 0; i < table->rows; ++i) {
+ mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
+
+ if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
+ ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_TABLE_GENERICPARAM]));
+
+ if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
+ ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
+
+ if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
+ ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
+ }
+}
+
static void
verify_tables_data (VerifyContext *ctx)
{
verify_manifest_resource_table (ctx);
CHECK_ERROR ();
verify_nested_class_table (ctx);
-}
-
-static gboolean
-mono_verifier_is_corlib (MonoImage *image)
-{
- gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ?
- TRUE : mono_security_core_clr_is_platform_image (image);
-
- return trusted_location && !strcmp ("mscorlib.dll", image->name);
+ CHECK_ERROR ();
+ verify_generic_param_table (ctx);
+ CHECK_ERROR ();
+ verify_method_spec_table (ctx);
+ CHECK_ERROR ();
+ verify_generic_param_constraint_table (ctx);
}
static void
ctx->valid = 1;
ctx->size = image->raw_data_len;
ctx->data = image->raw_data;
- ctx->is_corlib = mono_verifier_is_corlib (image);
}
static gboolean
return cleanup_context (&ctx, error_list);
}
+
+/*
+ * Verifies basic table constraints such as global table invariants (sorting, field monotonicity, etc).
+ * Other verification checks are meant to be done lazily by the runtime. Those include:
+ * blob items (signatures, method headers, custom attributes, etc)
+ * type semantics related
+ * vtable related
+ * stuff that should not block other pieces from running such as bad types/methods/fields/etc.
+ *
+ * The whole idea is that if this succeed the runtime is free to play around safely but any complex
+ * operation still need more checking.
+ */
gboolean
mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
{
return cleanup_context (&ctx, error_list);
}
+
+
+/*
+ * Verifies all other constraints.
+ */
+gboolean
+mono_verifier_verify_full_table_data (MonoImage *image, 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_typedef_table_full (&ctx);
+ CHECK_STATE ();
+ verify_field_table_full (&ctx);
+ CHECK_STATE ();
+ verify_method_table_full (&ctx);
+ CHECK_STATE ();
+ verify_memberref_table_full (&ctx);
+ CHECK_STATE ();
+ verify_cattr_table_full (&ctx);
+ CHECK_STATE ();
+ verify_field_marshal_table_full (&ctx);
+ CHECK_STATE ();
+ verify_decl_security_table_full (&ctx);
+ CHECK_STATE ();
+ verify_standalonesig_table_full (&ctx);
+ CHECK_STATE ();
+ verify_event_table_full (&ctx);
+ CHECK_STATE ();
+ verify_typespec_table_full (&ctx);
+ CHECK_STATE ();
+ verify_method_spec_table_full (&ctx);
+
+cleanup:
+ return cleanup_context (&ctx, error_list);
+}
+
+gboolean
+mono_verifier_verify_field_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;
+
+ is_valid_field_signature (&ctx, offset);
+ return cleanup_context (&ctx, error_list);
+}
+
+gboolean
+mono_verifier_verify_method_header (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;
+
+ is_valid_method_header (&ctx, offset);
+ return cleanup_context (&ctx, error_list);
+}
+
+gboolean
+mono_verifier_verify_method_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;
+
+ is_valid_method_signature (&ctx, offset);
+ return cleanup_context (&ctx, error_list);
+}
+
+gboolean
+mono_verifier_verify_memberref_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;
+
+ is_valid_method_or_field_signature (&ctx, offset);
+ return cleanup_context (&ctx, error_list);
+}
+
+gboolean
+mono_verifier_verify_standalone_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;
+
+ is_valid_standalonesig_blob (&ctx, offset);
+ return cleanup_context (&ctx, error_list);
+}
+
+gboolean
+mono_verifier_verify_typespec_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;
+
+ is_valid_typespec_blob (&ctx, offset);
+ return cleanup_context (&ctx, error_list);
+}
+
+gboolean
+mono_verifier_verify_methodspec_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;
+
+ is_valid_methodspec_blog (&ctx, offset);
+ return cleanup_context (&ctx, error_list);
+}
+
#else
gboolean
mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
{
return TRUE;
}
+
+gboolean
+mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
+{
+ return TRUE;
+}
+
+gboolean
+mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
+{
+ return TRUE;
+}
+
+gboolean
+mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
+{
+ return TRUE;
+}
+
+gboolean
+mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
+{
+ return TRUE;
+}
+
+gboolean
+mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
+{
+ return TRUE;
+}
+
+gboolean
+mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
+{
+ return TRUE;
+}
+
+gboolean
+mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, GSList **error_list)
+{
+ return TRUE;
+}
+
+gboolean
+mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
+{
+ return TRUE;
+}
+
#endif /* DISABLE_VERIFIER */