2 * metadata-verify.c: Metadata verfication support
5 * Mono Project (http://www.mono-project.com)
7 * Copyright (C) 2005-2008 Novell, Inc. (http://www.novell.com)
9 #include <mono/metadata/object-internals.h>
10 #include <mono/metadata/verify.h>
11 #include <mono/metadata/verify-internals.h>
12 #include <mono/metadata/opcodes.h>
13 #include <mono/metadata/tabledefs.h>
14 #include <mono/metadata/reflection.h>
15 #include <mono/metadata/debug-helpers.h>
16 #include <mono/metadata/mono-endian.h>
17 #include <mono/metadata/metadata.h>
18 #include <mono/metadata/metadata-internals.h>
19 #include <mono/metadata/class-internals.h>
20 #include <mono/metadata/tokentype.h>
21 #include <mono/metadata/security-manager.h>
22 #include <mono/metadata/security-core-clr.h>
23 #include <mono/metadata/cil-coff.h>
24 #include <mono/metadata/attrdefs.h>
25 #include <mono/utils/strenc.h>
30 #ifndef DISABLE_VERIFIER
32 TODO add fail fast mode
33 TODO add PE32+ support
34 TODO verify the entry point RVA and content.
35 TODO load_section_table and load_data_directories must take PE32+ into account
36 TODO add section relocation support
37 TODO verify the relocation table, since we really don't use, no need so far.
38 TODO do full PECOFF resources verification
39 TODO verify in the CLI header entry point and resources
40 TODO implement null token typeref validation
41 TODO verify table wide invariants for typedef (sorting and uniqueness)
42 TODO implement proper authenticode data directory validation
43 TODO verify properties that require multiple tables to be valid
44 FIXME use subtraction based bounds checking to avoid overflows
45 FIXME get rid of metadata_streams and other fields from VerifyContext
48 #ifdef MONO_VERIFIER_DEBUG
49 #define VERIFIER_DEBUG(code) do { code; } while (0)
51 #define VERIFIER_DEBUG(code)
54 #define INVALID_OFFSET ((guint32)-1)
55 #define INVALID_ADDRESS 0xffffffff
65 RESOURCE_TABLE_IDX = 2,
66 CERTIFICATE_TABLE_IDX = 4,
67 RELOCATION_TABLE_IDX = 5,
81 #define INVALID_TABLE (0xFF)
82 /*format: number of bits, number of tables, tables{n. tables} */
83 const static unsigned char coded_index_desc[] = {
84 #define TYPEDEF_OR_REF_DESC (0)
91 #define HAS_CONSTANT_DESC (TYPEDEF_OR_REF_DESC + 5)
98 #define HAS_CATTR_DESC (HAS_CONSTANT_DESC + 5)
106 MONO_TABLE_INTERFACEIMPL,
107 MONO_TABLE_MEMBERREF,
109 MONO_TABLE_DECLSECURITY,
112 MONO_TABLE_STANDALONESIG,
113 MONO_TABLE_MODULEREF,
116 MONO_TABLE_ASSEMBLYREF,
118 MONO_TABLE_EXPORTEDTYPE,
119 MONO_TABLE_MANIFESTRESOURCE,
121 #define HAS_FIELD_MARSHAL_DESC (HAS_CATTR_DESC + 21)
127 #define HAS_DECL_SECURITY_DESC (HAS_FIELD_MARSHAL_DESC + 4)
134 #define MEMBERREF_PARENT_DESC (HAS_DECL_SECURITY_DESC + 5)
143 #define HAS_SEMANTICS_DESC (MEMBERREF_PARENT_DESC + 7)
149 #define METHODDEF_OR_REF_DESC (HAS_SEMANTICS_DESC + 4)
153 MONO_TABLE_MEMBERREF,
155 #define MEMBER_FORWARDED_DESC (METHODDEF_OR_REF_DESC + 4)
161 #define IMPLEMENTATION_DESC (MEMBER_FORWARDED_DESC + 4)
165 MONO_TABLE_ASSEMBLYREF,
166 MONO_TABLE_EXPORTEDTYPE,
168 #define CATTR_TYPE_DESC (IMPLEMENTATION_DESC + 5)
174 MONO_TABLE_MEMBERREF,
177 #define RES_SCOPE_DESC (CATTR_TYPE_DESC + 7)
181 MONO_TABLE_MODULEREF,
182 MONO_TABLE_ASSEMBLYREF,
185 #define TYPE_OR_METHODDEF_DESC (RES_SCOPE_DESC + 6)
195 guint32 translated_offset;
207 guint32 rellocationsRVA;
208 guint16 numberOfRelocations;
223 gboolean report_error;
226 DataDirectory data_directories [16];
227 guint32 section_count;
228 SectionHeader *sections;
230 OffsetAndSize metadata_streams [5]; //offset from begin of the image
233 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception) \
235 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
236 vinfo->info.status = __status; \
237 vinfo->info.message = ( __msg); \
238 vinfo->exception_type = (__exception); \
239 (__ctx)->errors = g_slist_prepend ((__ctx)->errors, vinfo); \
243 #define ADD_ERROR(__ctx, __msg) \
245 if ((__ctx)->report_error) \
246 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
247 (__ctx)->valid = 0; \
251 #define FAIL(__ctx, __msg) \
253 if ((__ctx)->report_error) \
254 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
255 (__ctx)->valid = 0; \
259 #define CHECK_STATE() do { if (!ctx.valid) goto cleanup; } while (0)
261 #define CHECK_ERROR() do { if (!ctx->valid) return; } while (0)
263 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
264 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
266 #if SIZEOF_VOID_P == 4
267 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
269 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
272 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
273 #define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
276 dword_align (const char *ptr)
278 #if SIZEOF_VOID_P == 8
279 return (const char *) (((guint64) (ptr + 3)) & ~3);
281 return (const char *) (((guint32) (ptr + 3)) & ~3);
286 pe_signature_offset (VerifyContext *ctx)
288 return read32 (ctx->data + 0x3c);
292 pe_header_offset (VerifyContext *ctx)
294 return read32 (ctx->data + 0x3c) + 4;
298 bounds_check_virtual_address (VerifyContext *ctx, guint32 rva, guint32 size)
302 if (rva + size < rva) //overflow
305 if (ctx->stage > STAGE_PE) {
306 MonoCLIImageInfo *iinfo = ctx->image->image_info;
307 const int top = iinfo->cli_section_count;
308 MonoSectionTable *tables = iinfo->cli_section_tables;
311 for (i = 0; i < top; i++) {
312 guint32 base = tables->st_virtual_address;
313 guint32 end = base + tables->st_raw_data_size;
315 if (rva >= base && rva + size <= end)
318 /*if ((addr >= tables->st_virtual_address) &&
319 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
321 return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
331 for (i = 0; i < ctx->section_count; ++i) {
332 guint32 base = ctx->sections [i].baseRVA;
333 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
334 if (rva >= base && rva + size <= end)
341 bounds_check_datadir (DataDirectory *dir, guint32 offset, guint32 size)
343 if (dir->translated_offset > offset)
345 if (dir->size < size)
347 return offset + size <= dir->translated_offset + dir->size;
351 bounds_check_offset (OffsetAndSize *off, guint32 offset, guint32 size)
353 if (off->offset > offset)
356 if (off->size < size)
359 return offset + size <= off->offset + off->size;
363 translate_rva (VerifyContext *ctx, guint32 rva)
367 if (ctx->stage > STAGE_PE)
368 return mono_cli_rva_image_map (ctx->image, rva);
373 for (i = 0; i < ctx->section_count; ++i) {
374 guint32 base = ctx->sections [i].baseRVA;
375 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
376 if (rva >= base && rva <= end) {
377 guint32 res = (rva - base) + ctx->sections [i].baseOffset;
379 return res >= ctx->size ? INVALID_OFFSET : res;
383 return INVALID_OFFSET;
387 verify_msdos_header (VerifyContext *ctx)
391 ADD_ERROR (ctx, g_strdup ("Not enough space for the MS-DOS header"));
392 if (ctx->data [0] != 0x4d || ctx->data [1] != 0x5a)
393 ADD_ERROR (ctx, g_strdup ("Invalid MS-DOS watermark"));
394 lfanew = pe_signature_offset (ctx);
395 if (lfanew > ctx->size - 4)
396 ADD_ERROR (ctx, g_strdup ("MS-DOS lfanew offset points to outside of the file"));
400 verify_pe_header (VerifyContext *ctx)
402 guint32 offset = pe_signature_offset (ctx);
403 const char *pe_header = ctx->data + offset;
404 if (pe_header [0] != 'P' || pe_header [1] != 'E' ||pe_header [2] != 0 ||pe_header [3] != 0)
405 ADD_ERROR (ctx, g_strdup ("Invalid PE header watermark"));
409 if (offset > ctx->size - 20)
410 ADD_ERROR (ctx, g_strdup ("File with truncated pe header"));
411 if (read16 (pe_header) != 0x14c)
412 ADD_ERROR (ctx, g_strdup ("Invalid PE header Machine value"));
416 verify_pe_optional_header (VerifyContext *ctx)
418 guint32 offset = pe_header_offset (ctx);
419 guint32 header_size, file_alignment;
420 const char *pe_header = ctx->data + offset;
421 const char *pe_optional_header = pe_header + 20;
423 header_size = read16 (pe_header + 16);
426 if (header_size < 2) /*must be at least 2 or we won't be able to read magic*/
427 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
429 if (offset > ctx->size - header_size || header_size > ctx->size)
430 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
432 if (read16 (pe_optional_header) == 0x10b) {
433 if (header_size != 224)
434 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header size %d", header_size));
436 /* LAMESPEC MS plays around this value and ignore it during validation
437 if (read32 (pe_optional_header + 28) != 0x400000)
438 ADD_ERROR (ctx, g_strdup_printf ("Invalid Image base %x", read32 (pe_optional_header + 28)));*/
439 if (read32 (pe_optional_header + 32) != 0x2000)
440 ADD_ERROR (ctx, g_strdup_printf ("Invalid Section Aligmnent %x", read32 (pe_optional_header + 32)));
441 file_alignment = read32 (pe_optional_header + 36);
442 if (file_alignment != 0x200 && file_alignment != 0x1000)
443 ADD_ERROR (ctx, g_strdup_printf ("Invalid file Aligmnent %x", file_alignment));
444 /* All the junk in the middle is irrelevant, specially for mono. */
445 if (read32 (pe_optional_header + 92) > 0x10)
446 ADD_ERROR (ctx, g_strdup_printf ("Too many data directories %x", read32 (pe_optional_header + 92)));
448 if (read16 (pe_optional_header) == 0x20B)
449 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle PE32+"));
451 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header magic %d", read16 (pe_optional_header)));
456 load_section_table (VerifyContext *ctx)
459 SectionHeader *sections;
460 guint32 offset = pe_header_offset (ctx);
461 const char *ptr = ctx->data + offset;
462 guint16 num_sections = ctx->section_count = read16 (ptr + 2);
464 offset += 244;/*FIXME, this constant is different under PE32+*/
467 if (num_sections * 40 > ctx->size - offset)
468 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
470 sections = ctx->sections = g_new0 (SectionHeader, num_sections);
471 for (i = 0; i < num_sections; ++i) {
472 sections [i].size = read32 (ptr + 8);
473 sections [i].baseRVA = read32 (ptr + 12);
474 sections [i].baseOffset = read32 (ptr + 20);
475 sections [i].rellocationsRVA = read32 (ptr + 24);
476 sections [i].numberOfRelocations = read16 (ptr + 32);
480 ptr = ctx->data + offset; /*reset it to the beggining*/
481 for (i = 0; i < num_sections; ++i) {
482 guint32 raw_size, flags;
483 if (sections [i].baseOffset == 0)
484 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with intialized data only"));
485 if (sections [i].baseOffset >= ctx->size)
486 ADD_ERROR (ctx, g_strdup_printf ("Invalid PointerToRawData %x points beyond EOF", sections [i].baseOffset));
487 if (sections [i].size > ctx->size - sections [i].baseOffset)
488 ADD_ERROR (ctx, g_strdup ("Invalid VirtualSize points beyond EOF"));
490 raw_size = read32 (ptr + 16);
491 if (raw_size < sections [i].size)
492 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with SizeOfRawData < VirtualSize"));
494 if (raw_size > ctx->size - sections [i].baseOffset)
495 ADD_ERROR (ctx, g_strdup_printf ("Invalid SizeOfRawData %x points beyond EOF", raw_size));
497 if (sections [i].rellocationsRVA || sections [i].numberOfRelocations)
498 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't handle section relocation"));
500 flags = read32 (ptr + 36);
501 /*TODO 0xFE0000E0 is all flags from cil-coff.h OR'd. Make it a less magical number*/
502 if (flags == 0 || (flags & ~0xFE0000E0) != 0)
503 ADD_ERROR (ctx, g_strdup_printf ("Invalid section flags %x", flags));
510 is_valid_data_directory (int i)
512 /*LAMESPEC 4 == certificate 6 == debug, MS uses both*/
513 return i == 1 || i == 2 || i == 5 || i == 12 || i == 14 || i == 4 || i == 6;
517 load_data_directories (VerifyContext *ctx)
519 guint32 offset = pe_header_offset (ctx) + 116; /*FIXME, this constant is different under PE32+*/
520 const char *ptr = ctx->data + offset;
523 for (i = 0; i < 16; ++i) {
524 guint32 rva = read32 (ptr);
525 guint32 size = read32 (ptr + 4);
527 /*LAMESPEC the authenticode data directory format is different. We don't support CAS, so lets ignore for now.*/
528 if (i == CERTIFICATE_TABLE_IDX) {
532 if ((rva != 0 || size != 0) && !is_valid_data_directory (i))
533 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d", i));
535 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
536 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d rva/size pair %x/%x", i, rva, size));
538 ctx->data_directories [i].rva = rva;
539 ctx->data_directories [i].size = size;
540 ctx->data_directories [i].translated_offset = translate_rva (ctx, rva);
546 #define SIZE_OF_MSCOREE (sizeof ("mscoree.dll"))
548 #define SIZE_OF_CORMAIN (sizeof ("_CorExeMain"))
551 verify_hint_name_table (VerifyContext *ctx, guint32 import_rva, const char *table_name)
554 guint32 hint_table_rva;
556 import_rva = translate_rva (ctx, import_rva);
557 g_assert (import_rva != INVALID_OFFSET);
559 hint_table_rva = read32 (ctx->data + import_rva);
560 if (!bounds_check_virtual_address (ctx, hint_table_rva, SIZE_OF_CORMAIN + 2))
561 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint/Name rva %d for %s", hint_table_rva, table_name));
563 hint_table_rva = translate_rva (ctx, hint_table_rva);
564 g_assert (hint_table_rva != INVALID_OFFSET);
565 ptr = ctx->data + hint_table_rva + 2;
567 if (memcmp ("_CorExeMain", ptr, SIZE_OF_CORMAIN) && memcmp ("_CorDllMain", ptr, SIZE_OF_CORMAIN)) {
568 char name[SIZE_OF_CORMAIN];
569 memcpy (name, ptr, SIZE_OF_CORMAIN);
570 name [SIZE_OF_CORMAIN - 1] = 0;
571 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint / Name: '%s'", name));
576 verify_import_table (VerifyContext *ctx)
578 DataDirectory it = ctx->data_directories [IMPORT_TABLE_IDX];
579 guint32 offset = it.translated_offset;
580 const char *ptr = ctx->data + offset;
581 guint32 name_rva, ilt_rva, iat_rva;
583 g_assert (offset != INVALID_OFFSET);
586 ADD_ERROR (ctx, g_strdup_printf ("Import table size %d is smaller than 40", it.size));
588 ilt_rva = read32 (ptr);
589 if (ilt_rva && !bounds_check_virtual_address (ctx, ilt_rva, 8))
590 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Lookup Table rva %x", ilt_rva));
592 name_rva = read32 (ptr + 12);
593 if (name_rva && !bounds_check_virtual_address (ctx, name_rva, SIZE_OF_MSCOREE))
594 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name rva %x", name_rva));
596 iat_rva = read32 (ptr + 16);
598 if (!bounds_check_virtual_address (ctx, iat_rva, 8))
599 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Address Table rva %x", iat_rva));
601 if (iat_rva != ctx->data_directories [IAT_IDX].rva)
602 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));
606 name_rva = translate_rva (ctx, name_rva);
607 g_assert (name_rva != INVALID_OFFSET);
608 ptr = ctx->data + name_rva;
610 if (memcmp ("mscoree.dll", ptr, SIZE_OF_MSCOREE)) {
611 char name[SIZE_OF_MSCOREE];
612 memcpy (name, ptr, SIZE_OF_MSCOREE);
613 name [SIZE_OF_MSCOREE - 1] = 0;
614 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name: '%s'", name));
619 verify_hint_name_table (ctx, ilt_rva, "Import Lookup Table");
624 verify_hint_name_table (ctx, iat_rva, "Import Address Table");
628 verify_resources_table (VerifyContext *ctx)
630 DataDirectory it = ctx->data_directories [RESOURCE_TABLE_IDX];
632 guint16 named_entries, id_entries;
633 const char *ptr, *root, *end;
639 ADD_ERROR (ctx, g_strdup_printf ("Resource section is too small, must be at least 16 bytes long but it's %d long", it.size));
641 offset = it.translated_offset;
642 root = ptr = ctx->data + offset;
643 end = root + it.size;
645 g_assert (offset != INVALID_OFFSET);
647 named_entries = read16 (ptr + 12);
648 id_entries = read16 (ptr + 14);
650 if ((named_entries + id_entries) * 8 + 16 > it.size)
651 ADD_ERROR (ctx, g_strdup_printf ("Resource section is too small, the number of entries (%d) doesn't fit on it's size %d", named_entries + id_entries, it.size));
653 /* XXX at least one unmanaged resource is added due to a call to AssemblyBuilder::DefineVersionInfoResource ()
654 if (named_entries || id_entries)
655 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support full verification of PECOFF resources"));
659 /*----------nothing from here on can use data_directory---*/
662 get_data_dir (VerifyContext *ctx, int idx)
664 MonoCLIImageInfo *iinfo = ctx->image->image_info;
665 MonoPEDirEntry *entry= &iinfo->cli_header.datadir.pe_export_table;
669 res.rva = entry->rva;
670 res.size = entry->size;
671 res.translated_offset = translate_rva (ctx, res.rva);
676 verify_cli_header (VerifyContext *ctx)
678 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
684 ADD_ERROR (ctx, g_strdup_printf ("CLI header missing"));
687 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size in data directory %d must be 72", it.size));
689 offset = it.translated_offset;
690 ptr = ctx->data + offset;
692 g_assert (offset != INVALID_OFFSET);
694 if (read16 (ptr) != 72)
695 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size %d must be 72", read16 (ptr)));
697 if (!bounds_check_virtual_address (ctx, read32 (ptr + 8), read32 (ptr + 12)))
698 ADD_ERROR (ctx, g_strdup_printf ("Invalid medatata section rva/size pair %x/%x", read32 (ptr + 8), read32 (ptr + 12)));
701 if (!read32 (ptr + 8) || !read32 (ptr + 12))
702 ADD_ERROR (ctx, g_strdup_printf ("Missing medatata section in the CLI header"));
704 if ((read32 (ptr + 16) & ~0x0001000B) != 0)
705 ADD_ERROR (ctx, g_strdup_printf ("Invalid CLI header flags"));
708 for (i = 0; i < 6; ++i) {
709 guint32 rva = read32 (ptr);
710 guint32 size = read32 (ptr + 4);
712 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
713 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli section %i rva/size pair %x/%x", i, rva, size));
718 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't support cli header section %d", i));
723 pad4 (guint32 offset)
725 if (offset & 0x3) //pad to the next 4 byte boundary
726 offset = (offset & ~0x3) + 4;
731 verify_metadata_header (VerifyContext *ctx)
734 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
738 offset = it.translated_offset;
739 ptr = ctx->data + offset;
740 g_assert (offset != INVALID_OFFSET);
742 //build a directory entry for the metadata root
744 it.rva = read32 (ptr);
746 it.size = read32 (ptr);
747 it.translated_offset = offset = translate_rva (ctx, it.rva);
749 ptr = ctx->data + offset;
750 g_assert (offset != INVALID_OFFSET);
753 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small %d (at least 20 bytes required for initial decoding)", it.size));
755 if (read32 (ptr) != 0x424A5342)
756 ADD_ERROR (ctx, g_strdup_printf ("Invalid metadata signature, expected 0x424A5342 but got %08x", read32 (ptr)));
758 offset = pad4 (offset + 16 + read32 (ptr + 12));
760 if (!bounds_check_datadir (&it, offset, 4))
761 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small %d (at least %d bytes required for flags decoding)", it.size, offset + 4 - it.translated_offset));
763 ptr = ctx->data + offset; //move to streams header
765 if (read16 (ptr + 2) < 3)
766 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section must have at least 3 streams (#~, #GUID and #Blob"));
771 for (i = 0; i < 5; ++i) {
772 guint32 stream_off, stream_size;
773 int string_size, stream_idx;
775 if (!bounds_check_datadir (&it, offset, 8))
776 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small for initial decode of stream header %d, missing %d bytes", i, offset + 9 - it.translated_offset));
778 stream_off = it.translated_offset + read32 (ptr);
779 stream_size = read32 (ptr + 4);
781 if (!bounds_check_datadir (&it, stream_off, stream_size))
782 ADD_ERROR (ctx, g_strdup_printf ("Invalid stream header %d offset/size pair %x/%x", 0, stream_off, stream_size));
787 for (string_size = 0; string_size < 32; ++string_size) {
788 if (!bounds_check_datadir (&it, offset++, 1))
789 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small to decode stream header %d name", i));
790 if (!ptr [string_size])
794 if (ptr [string_size])
795 ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d name larger than 32 bytes", i));
797 if (!strncmp ("#Strings", ptr, 9))
798 stream_idx = STRINGS_STREAM;
799 else if (!strncmp ("#US", ptr, 4))
800 stream_idx = USER_STRINGS_STREAM;
801 else if (!strncmp ("#Blob", ptr, 6))
802 stream_idx = BLOB_STREAM;
803 else if (!strncmp ("#GUID", ptr, 6))
804 stream_idx = GUID_STREAM;
805 else if (!strncmp ("#~", ptr, 3))
806 stream_idx = TILDE_STREAM;
808 ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d invalid name %s", i, ptr));
810 if (ctx->metadata_streams [stream_idx].offset != 0)
811 ADD_ERROR (ctx, g_strdup_printf ("Duplicated metadata stream header %s", ptr));
813 ctx->metadata_streams [stream_idx].offset = stream_off;
814 ctx->metadata_streams [stream_idx].size = stream_size;
816 offset = pad4 (offset);
817 ptr = ctx->data + offset;
820 if (!ctx->metadata_streams [TILDE_STREAM].size)
821 ADD_ERROR (ctx, g_strdup_printf ("Metadata #~ stream missing"));
822 if (!ctx->metadata_streams [GUID_STREAM].size)
823 ADD_ERROR (ctx, g_strdup_printf ("Metadata guid stream missing"));
824 if (!ctx->metadata_streams [BLOB_STREAM].size)
825 ADD_ERROR (ctx, g_strdup_printf ("Metadata blob stream missing"));
830 verify_tables_schema (VerifyContext *ctx)
832 OffsetAndSize tables_area = ctx->metadata_streams [TILDE_STREAM];
833 unsigned offset = tables_area.offset;
834 const char *ptr = ctx->data + offset;
835 guint64 valid_tables;
839 //printf ("tables_area size %d offset %x %s\n", tables_area.size, tables_area.offset, ctx->image->name);
840 if (tables_area.size < 24)
841 ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for initial decoding (requires 24 bytes)", tables_area.size));
843 //printf ("ptr %x %x\n", ptr[4], ptr[5]);
844 if (ptr [4] != 2 && ptr [4] != 1)
845 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata major version %d, expected 2", ptr [4]));
847 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata minor version %d, expected 0", ptr [5]));
849 if ((ptr [6] & ~0x7) != 0)
850 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata heap sizes 0x%02x, only bits 0, 1 and 2 can be set", ((unsigned char *) ptr) [6]));
852 valid_tables = read64 (ptr + 8);
854 for (i = 0; i < 64; ++i) {
855 if (!(valid_tables & ((guint64)1 << i)))
858 /*MS Extensions: 0x3 0x5 0x7 0x13 0x16
859 Unused: 0x1E 0x1F 0x2D-0x3F
860 We don't care about the MS extensions.*/
861 if (i == 0x3 || i == 0x5 || i == 0x7 || i == 0x13 || i == 0x16)
862 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifies doesn't support MS specific table %x", i));
863 if (i == 0x1E || i == 0x1F || i >= 0x2D)
864 ADD_ERROR (ctx, g_strdup_printf ("Invalid table %x", i));
868 if (tables_area.size < 24 + count * 4)
869 ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for decoding row counts (requires %d bytes)", tables_area.size, 24 + count * 4));
872 for (i = 0; i < 64; ++i) {
873 if (valid_tables & ((guint64)1 << i)) {
874 guint32 row_count = read32 (ptr);
875 if (row_count > (1 << 24) - 1)
876 ADD_ERROR (ctx, g_strdup_printf ("Invalid Table %d row count: %d. Mono only supports 16777215 rows", i, row_count));
882 /*----------nothing from here on can use data_directory or metadata_streams ---*/
885 get_col_offset (VerifyContext *ctx, int table, int column)
887 guint32 bitfield = ctx->image->tables [table].size_bitfield;
891 offset += mono_metadata_table_size (bitfield, column);
897 get_col_size (VerifyContext *ctx, int table, int column)
899 return mono_metadata_table_size (ctx->image->tables [table].size_bitfield, column);
903 get_metadata_stream (VerifyContext *ctx, MonoStreamHeader *header)
906 res.offset = header->data - ctx->data;
907 res.size = header->size;
913 is_valid_string_full (VerifyContext *ctx, guint32 offset, gboolean allow_empty)
915 OffsetAndSize strings = get_metadata_stream (ctx, &ctx->image->heap_strings);
917 const char *data = ctx->data + strings.offset;
919 if (offset >= strings.size)
921 if (data + offset < data) //FIXME, use a generalized and smart unsigned add with overflow check and fix the whole thing
924 if (!mono_utf8_validate_and_len_with_bounds (data + offset, strings.size - offset, &length, NULL))
926 return allow_empty || length > 0;
930 is_valid_string (VerifyContext *ctx, guint32 offset)
932 return is_valid_string_full (ctx, offset, TRUE);
936 is_valid_non_empty_string (VerifyContext *ctx, guint32 offset)
938 return is_valid_string_full (ctx, offset, FALSE);
942 is_valid_guid (VerifyContext *ctx, guint32 offset)
944 OffsetAndSize guids = get_metadata_stream (ctx, &ctx->image->heap_guid);
945 return guids.size >= 8 && guids.size - 8 >= offset;
949 get_coded_index_token (int token_kind, guint32 coded_token)
951 guint32 bits = coded_index_desc [token_kind];
952 return coded_token >> bits;
956 get_coded_index_table (int kind, guint32 coded_token)
958 guint32 idx, bits = coded_index_desc [kind];
960 idx = coded_token & ((1 << bits) - 1);
961 return coded_index_desc [kind + idx];
965 make_coded_token (int kind, guint32 table, guint32 table_idx)
967 guint32 bits = coded_index_desc [kind++];
968 guint32 tables = coded_index_desc [kind++];
970 for (i = 0; i < tables; ++i) {
971 if (coded_index_desc [kind++] == table)
972 return ((table_idx + 1) << bits) | i;
974 g_assert_not_reached ();
979 is_valid_coded_index (VerifyContext *ctx, int token_kind, guint32 coded_token)
981 guint32 bits = coded_index_desc [token_kind++];
982 guint32 table_count = coded_index_desc [token_kind++];
983 guint32 table = coded_token & ((1 << bits) - 1);
984 guint32 token = coded_token >> bits;
986 if (table >= table_count)
989 /*token_kind points to the first table idx*/
990 table = coded_index_desc [token_kind + table];
992 if (table == INVALID_TABLE)
994 return token <= ctx->image->tables [table].rows;
1001 MonoTableInfo *table;
1005 token_locator (const void *a, const void *b)
1007 RowLocator *loc = (RowLocator *)a;
1008 unsigned const char *row = (unsigned const char *)b;
1009 guint32 token = loc->col_size == 2 ? read16 (row + loc->col_offset) : read32 (row + loc->col_offset);
1011 VERIFIER_DEBUG ( printf ("\tfound token %x at idx %d\n", token, ((const char*)row - loc->table->base) / loc->table->row_size) );
1012 return (int)loc->token - (int)token;
1016 search_sorted_table (VerifyContext *ctx, int table, int column, guint32 coded_token)
1018 MonoTableInfo *tinfo = &ctx->image->tables [table];
1020 const char *res, *base;
1021 locator.token = coded_token;
1022 locator.col_offset = get_col_offset (ctx, table, column);
1023 locator.col_size = get_col_size (ctx, table, column);
1024 locator.table = tinfo;
1028 VERIFIER_DEBUG ( printf ("looking token %x table %d col %d rsize %d roff %d\n", coded_token, table, column, locator.col_size, locator.col_offset) );
1029 res = bsearch (&locator, base, tinfo->rows, tinfo->row_size, token_locator);
1033 return (res - base) / tinfo->row_size;
1036 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1038 get_string_ptr (VerifyContext *ctx, guint offset)
1040 return ctx->image->heap_strings.data + offset;
1043 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1045 string_cmp (VerifyContext *ctx, const char *str, guint offset)
1048 return strcmp (str, "");
1050 return strcmp (str, get_string_ptr (ctx, offset));
1054 mono_verifier_is_corlib (MonoImage *image)
1056 gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ?
1057 TRUE : mono_security_core_clr_is_platform_image (image);
1059 return trusted_location && image->module_name && !strcmp ("mscorlib.dll", image->module_name);
1063 typedef_is_system_object (VerifyContext *ctx, guint32 *data)
1065 return mono_verifier_is_corlib (ctx->image) && !string_cmp (ctx, "System", data [MONO_TYPEDEF_NAMESPACE]) && !string_cmp (ctx, "Object", data [MONO_TYPEDEF_NAME]);
1069 decode_value (const char *_ptr, unsigned available, unsigned *value, unsigned *size)
1072 const unsigned char *ptr = (const unsigned char *)_ptr;
1080 if ((b & 0x80) == 0) {
1083 } else if ((b & 0x40) == 0) {
1087 *value = ((b & 0x3f) << 8 | ptr [1]);
1092 *value = ((b & 0x1f) << 24) |
1102 decode_signature_header (VerifyContext *ctx, guint32 offset, int *size, const char **first_byte)
1104 MonoStreamHeader blob = ctx->image->heap_blob;
1105 guint32 value, enc_size;
1107 if (offset >= blob.size)
1110 if (!decode_value (blob.data + offset, blob.size - offset, &value, &enc_size))
1113 if (offset + enc_size + value < offset)
1116 if (offset + enc_size + value > blob.size)
1120 *first_byte = blob.data + offset + enc_size;
1125 safe_read (const char **_ptr, const char *limit, void *dest, int size)
1127 const char *ptr = *_ptr;
1128 if (ptr + size > limit)
1132 *((guint8*)dest) = *((guint8*)ptr);
1136 *((guint16*)dest) = read16 (ptr);
1140 *((guint32*)dest) = read32 (ptr);
1149 safe_read_compressed_int (const char **_ptr, const char *limit, unsigned *dest)
1152 const char *ptr = *_ptr;
1153 gboolean res = decode_value (ptr, limit - ptr, dest, &size);
1158 #define safe_read8(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 1)
1159 #define safe_read_cint(VAR, PTR, LIMIT) safe_read_compressed_int (&PTR, LIMIT, &VAR)
1160 #define safe_read16(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 2)
1161 #define safe_read32(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 4)
1164 parse_type (VerifyContext *ctx, const char **_ptr, const char *end);
1167 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged);
1170 parse_custom_mods (VerifyContext *ctx, const char **_ptr, const char *end)
1172 const char *ptr = *_ptr;
1177 if (!safe_read8 (type, ptr, end))
1178 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the type"));
1180 if (type != MONO_TYPE_CMOD_REQD && type != MONO_TYPE_CMOD_OPT) {
1185 if (!safe_read_cint (token, ptr, end))
1186 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the token"));
1188 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1189 FAIL (ctx, g_strdup_printf ("CustomMod: invalid TypeDefOrRef token %x", token));
1197 parse_array_shape (VerifyContext *ctx, const char **_ptr, const char *end)
1199 const char *ptr = *_ptr;
1201 guint32 size, num, i;
1203 if (!safe_read8 (val, ptr, end))
1204 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for Rank"));
1207 FAIL (ctx, g_strdup ("ArrayShape: Invalid shape with zero Rank"));
1209 if (!safe_read_cint (size, ptr, end))
1210 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumSizes"));
1212 for (i = 0; i < size; ++i) {
1213 if (!safe_read_cint (num, ptr, end))
1214 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for Size of rank %d", i + 1));
1217 if (!safe_read_cint (size, ptr, end))
1218 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumLoBounds"));
1220 for (i = 0; i < size; ++i) {
1221 if (!safe_read_cint (num, ptr, end))
1222 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for LoBound of rank %d", i + 1));
1230 parse_generic_inst (VerifyContext *ctx, const char **_ptr, const char *end)
1232 const char *ptr = *_ptr;
1234 guint32 count, token, i;
1236 if (!safe_read8 (type, ptr, end))
1237 FAIL (ctx, g_strdup ("GenericInst: Not enough room for kind"));
1239 if (type != MONO_TYPE_CLASS && type != MONO_TYPE_VALUETYPE)
1240 FAIL (ctx, g_strdup_printf ("GenericInst: Invalid GenericInst kind %x\n", type));
1242 if (!safe_read_cint (token, ptr, end))
1243 FAIL (ctx, g_strdup ("GenericInst: Not enough room for type token"));
1245 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1246 FAIL (ctx, g_strdup_printf ("GenericInst: invalid TypeDefOrRef token %x", token));
1248 if (!safe_read_cint (count, ptr, end))
1249 FAIL (ctx, g_strdup ("GenericInst: Not enough room for argument count"));
1252 FAIL (ctx, g_strdup ("GenericInst: Zero arguments generic instance"));
1254 for (i = 0; i < count; ++i) {
1255 if (!parse_type (ctx, &ptr, end))
1256 FAIL (ctx, g_strdup_printf ("GenericInst: invalid generic argument %d", i + 1));
1263 parse_type (VerifyContext *ctx, const char **_ptr, const char *end)
1265 const char *ptr = *_ptr;
1269 if (!safe_read8 (type, ptr, end))
1270 FAIL (ctx, g_strdup ("Type: Not enough room for the type"));
1272 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_PTR) ||
1273 (type >= MONO_TYPE_VALUETYPE && type <= MONO_TYPE_GENERICINST) ||
1274 (type >= MONO_TYPE_I && type <= MONO_TYPE_U) ||
1275 (type >= MONO_TYPE_FNPTR && type <= MONO_TYPE_MVAR)))
1276 FAIL (ctx, g_strdup_printf ("Type: Invalid type kind %x\n", type));
1280 if (!parse_custom_mods (ctx, &ptr, end))
1281 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1283 if (!safe_read8 (type, ptr, end))
1284 FAIL (ctx, g_strdup ("Type: Not enough room to parse the pointer type"));
1286 if (type != MONO_TYPE_VOID) {
1288 if (!parse_type (ctx, &ptr, end))
1289 FAIL (ctx, g_strdup ("Type: Could not parse pointer type"));
1293 case MONO_TYPE_VALUETYPE:
1294 case MONO_TYPE_CLASS:
1295 if (!safe_read_cint (token, ptr, end))
1296 FAIL (ctx, g_strdup ("Type: Not enough room for the type token"));
1298 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1299 FAIL (ctx, g_strdup_printf ("Type: invalid TypeDefOrRef token %x", token));
1303 case MONO_TYPE_MVAR:
1304 if (!safe_read_cint (token, ptr, end))
1305 FAIL (ctx, g_strdup ("Type: Not enough room for to decode generic argument number"));
1308 case MONO_TYPE_ARRAY:
1309 if (!parse_type (ctx, &ptr, end))
1310 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1311 if (!parse_array_shape (ctx, &ptr, end))
1312 FAIL (ctx, g_strdup ("Type: Could not parse array shape"));
1315 case MONO_TYPE_GENERICINST:
1316 if (!parse_generic_inst (ctx, &ptr, end))
1317 FAIL (ctx, g_strdup ("Type: Could not parse generic inst"));
1320 case MONO_TYPE_FNPTR:
1321 if (!parse_method_signature (ctx, &ptr, end, TRUE, TRUE))
1322 FAIL (ctx, g_strdup ("Type: Could not parse method pointer signature"));
1325 case MONO_TYPE_SZARRAY:
1326 if (!parse_custom_mods (ctx, &ptr, end))
1327 FAIL (ctx, g_strdup ("Type: Failed to parse array element custom attr"));
1328 if (!parse_type (ctx, &ptr, end))
1329 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1337 parse_return_type (VerifyContext *ctx, const char **_ptr, const char *end)
1342 if (!parse_custom_mods (ctx, _ptr, end))
1346 if (!safe_read8 (type, ptr, end))
1347 FAIL (ctx, g_strdup ("ReturnType: Not enough room for the type"));
1349 if (type == MONO_TYPE_VOID || type == MONO_TYPE_TYPEDBYREF) {
1354 //it's a byref, update the cursor ptr
1355 if (type == MONO_TYPE_BYREF)
1358 return parse_type (ctx, _ptr, end);
1362 parse_param (VerifyContext *ctx, const char **_ptr, const char *end)
1367 if (!parse_custom_mods (ctx, _ptr, end))
1371 if (!safe_read8 (type, ptr, end))
1372 FAIL (ctx, g_strdup ("Param: Not enough room for the type"));
1374 if (type == MONO_TYPE_TYPEDBYREF) {
1379 //it's a byref, update the cursor ptr
1380 if (type == MONO_TYPE_BYREF)
1383 return parse_type (ctx, _ptr, end);
1387 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged)
1390 unsigned param_count = 0, gparam_count = 0, type = 0, i;
1391 const char *ptr = *_ptr;
1392 gboolean saw_sentinel = FALSE;
1394 if (!safe_read8 (cconv, ptr, end))
1395 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the call conv"));
1398 FAIL (ctx, g_strdup ("MethodSig: CallConv has 0x80 set"));
1400 if (allow_unmanaged) {
1401 if ((cconv & 0x0F) > MONO_CALL_VARARG)
1402 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not valid, it's %x", cconv & 0x0F));
1403 } else if ((cconv & 0x0F) != MONO_CALL_DEFAULT && (cconv & 0x0F) != MONO_CALL_VARARG)
1404 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not Default or Vararg, it's %x", cconv & 0x0F));
1406 if ((cconv & 0x10) && !safe_read_cint (gparam_count, ptr, end))
1407 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the generic param count"));
1409 if ((cconv & 0x10) && gparam_count == 0)
1410 FAIL (ctx, g_strdup ("MethodSig: Signature with generics but zero arity"));
1412 if (allow_unmanaged && (cconv & 0x10))
1413 FAIL (ctx, g_strdup ("MethodSig: Standalone signature with generic params"));
1415 if (!safe_read_cint (param_count, ptr, end))
1416 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the param count"));
1418 if (!parse_return_type (ctx, &ptr, end))
1419 FAIL (ctx, g_strdup ("MethodSig: Error parsing return type"));
1421 for (i = 0; i < param_count; ++i) {
1422 if (allow_sentinel) {
1423 if (!safe_read8 (type, ptr, end))
1424 FAIL (ctx, g_strdup_printf ("MethodSig: Not enough room for param %d type", i));
1426 if (type == MONO_TYPE_SENTINEL) {
1427 if ((cconv & 0x0F) != MONO_CALL_VARARG)
1428 FAIL (ctx, g_strdup ("MethodSig: Found sentinel but signature is not vararg"));
1431 FAIL (ctx, g_strdup ("MethodSig: More than one sentinel type"));
1433 saw_sentinel = TRUE;
1439 if (!parse_param (ctx, &ptr, end))
1440 FAIL (ctx, g_strdup_printf ("MethodSig: Error parsing arg %d", i));
1448 parse_property_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1451 unsigned param_count = 0, i;
1452 const char *ptr = *_ptr;
1454 if (!safe_read8 (sig, ptr, end))
1455 FAIL (ctx, g_strdup ("PropertySig: Not enough room for signature"));
1457 if (sig != 0x08 && sig != 0x28)
1458 FAIL (ctx, g_strdup_printf ("PropertySig: Signature is not 0x28 or 0x08: %x", sig));
1460 if (!safe_read_cint (param_count, ptr, end))
1461 FAIL (ctx, g_strdup ("PropertySig: Not enough room for the param count"));
1463 if (!parse_custom_mods (ctx, &ptr, end))
1466 if (!parse_type (ctx, &ptr, end))
1467 FAIL (ctx, g_strdup ("PropertySig: Could not parse property type"));
1469 for (i = 0; i < param_count; ++i) {
1470 if (!parse_type (ctx, &ptr, end))
1471 FAIL (ctx, g_strdup_printf ("PropertySig: Error parsing arg %d", i));
1479 parse_field (VerifyContext *ctx, const char **_ptr, const char *end)
1481 const char *ptr = *_ptr;
1482 guint8 signature = 0;
1484 if (!safe_read8 (signature, ptr, end))
1485 FAIL (ctx, g_strdup ("Field: Not enough room for field signature"));
1487 if (signature != 0x06)
1488 FAIL (ctx, g_strdup_printf ("Field: Invalid signature 0x%x, must be 6", signature));
1491 if (!parse_custom_mods (ctx, _ptr, end))
1494 return parse_type (ctx, _ptr, end);
1498 parse_locals_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1501 unsigned locals_count = 0, i;
1502 const char *ptr = *_ptr;
1504 if (!safe_read8 (sig, ptr, end))
1505 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for signature"));
1508 FAIL (ctx, g_strdup_printf ("LocalsSig: Signature is not 0x28 or 0x08: %x", sig));
1510 if (!safe_read_cint (locals_count, ptr, end))
1511 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for the param count"));
1513 if (locals_count == 0)
1514 FAIL (ctx, g_strdup ("LocalsSig: Signature with zero locals"));
1516 for (i = 0; i < locals_count; ++i) {
1517 if (!safe_read8 (sig, ptr, end))
1518 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1520 if (sig == MONO_TYPE_TYPEDBYREF)
1523 while (sig == MONO_TYPE_CMOD_REQD || sig == MONO_TYPE_CMOD_OPT || sig == MONO_TYPE_PINNED) {
1524 if (sig != MONO_TYPE_PINNED && !parse_custom_mods (ctx, &ptr, end))
1525 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1526 if (!safe_read8 (sig, ptr, end))
1527 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1530 if (!parse_type (ctx, &ptr, end))
1531 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1539 is_valid_field_signature (VerifyContext *ctx, guint32 offset)
1541 int size = 0, signature = 0;
1542 const char *ptr = NULL, *end;
1544 if (!decode_signature_header (ctx, offset, &size, &ptr))
1545 FAIL (ctx, g_strdup ("FieldSig: Could not decode signature header"));
1548 if (!safe_read8 (signature, ptr, end))
1549 FAIL (ctx, g_strdup ("FieldSig: Not enough room for the signature"));
1552 FAIL (ctx, g_strdup_printf ("FieldSig: Invalid signature %x", signature));
1555 return parse_field (ctx, &ptr, end);
1559 is_valid_method_signature (VerifyContext *ctx, guint32 offset)
1562 const char *ptr = NULL, *end;
1564 if (!decode_signature_header (ctx, offset, &size, &ptr))
1565 FAIL (ctx, g_strdup ("MethodSig: Could not decode signature header"));
1568 return parse_method_signature (ctx, &ptr, end, FALSE, FALSE);
1572 is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
1575 unsigned signature = 0;
1576 const char *ptr = NULL, *end;
1578 if (!decode_signature_header (ctx, offset, &size, &ptr))
1579 FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
1582 if (!safe_read8 (signature, ptr, end))
1583 FAIL (ctx, g_strdup ("MemberRefSig: Not enough room for the call conv"));
1586 if (signature == 0x06)
1587 return parse_field (ctx, &ptr, end);
1589 return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1593 is_vald_cattr_blob (VerifyContext *ctx, guint32 offset)
1597 const char *ptr = NULL, *end;
1602 if (!decode_signature_header (ctx, offset, &size, &ptr))
1603 FAIL (ctx, g_strdup ("CustomAttribute: Could not decode signature header"));
1606 if (!safe_read16 (prolog, ptr, end))
1607 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1610 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1616 is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
1618 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1619 //TODO do proper verification
1620 return blob.size >= 1 && blob.size - 1 >= offset;
1624 is_valid_permission_set (VerifyContext *ctx, guint32 offset)
1626 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1627 //TODO do proper verification
1628 return blob.size >= 1 && blob.size - 1 >= offset;
1632 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
1635 unsigned signature = 0;
1636 const char *ptr = NULL, *end;
1638 if (!decode_signature_header (ctx, offset, &size, &ptr))
1639 FAIL (ctx, g_strdup ("StandAloneSig: Could not decode signature header"));
1642 if (!safe_read8 (signature, ptr, end))
1643 FAIL (ctx, g_strdup ("StandAloneSig: Not enough room for the call conv"));
1646 if (signature == 0x07)
1647 return parse_locals_signature (ctx, &ptr, end);
1648 return parse_method_signature (ctx, &ptr, end, TRUE, TRUE);
1652 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
1655 const char *ptr = NULL, *end;
1657 if (!decode_signature_header (ctx, offset, &size, &ptr))
1658 FAIL (ctx, g_strdup ("PropertySig: Could not decode signature header"));
1661 return parse_property_signature (ctx, &ptr, end);
1665 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
1668 const char *ptr = NULL, *end;
1672 if (!decode_signature_header (ctx, offset, &size, &ptr))
1673 FAIL (ctx, g_strdup ("TypeSpec: Could not decode signature header"));
1676 if (!parse_custom_mods (ctx, &ptr, end))
1679 if (!safe_read8 (type, ptr, end))
1680 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for type"));
1683 if (type == MONO_TYPE_TYPEDBYREF)
1686 return parse_type (ctx, &ptr, end);
1690 is_valid_methodspec_blog (VerifyContext *ctx, guint32 offset)
1693 const char *ptr = NULL, *end;
1695 guint32 count = 0, i;
1697 if (!decode_signature_header (ctx, offset, &size, &ptr))
1698 FAIL (ctx, g_strdup ("MethodSpec: Could not decode signature header"));
1701 if (!safe_read8 (type, ptr, end))
1702 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for call convention"));
1705 FAIL (ctx, g_strdup_printf ("MethodSpec: Invalid call convention 0x%x, expected 0x0A", type));
1707 if (!safe_read_cint (count, ptr, end))
1708 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for parameter count"));
1711 FAIL (ctx, g_strdup ("MethodSpec: Zero generic argument count"));
1713 for (i = 0; i < count; ++i) {
1714 if (!parse_type (ctx, &ptr, end))
1715 FAIL (ctx, g_strdup_printf ("MethodSpec: Could not parse parameter %d", i + 1));
1721 is_valid_blob_object (VerifyContext *ctx, guint32 offset)
1723 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1724 guint32 entry_size, bytes;
1726 if (blob.size < offset)
1729 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1732 if (offset + entry_size + bytes < offset)
1735 return blob.size >= offset + entry_size + bytes;
1739 is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
1741 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1742 guint32 size, entry_size, bytes;
1744 if (blob.size < offset)
1745 FAIL (ctx, g_strdup ("ContantValue: invalid offset"));
1747 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1748 FAIL (ctx, g_strdup ("ContantValue: not enough space to decode size"));
1750 if (type == MONO_TYPE_STRING) {
1751 //String is encoded as: compressed_int:len len *bytes
1754 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size))
1755 FAIL (ctx, g_strdup_printf ("ContantValue: not enough space for string, required %d but got %d", entry_size * 2, blob.size - offset));
1761 case MONO_TYPE_BOOLEAN:
1766 case MONO_TYPE_CHAR:
1774 case MONO_TYPE_CLASS:
1784 g_assert_not_reached ();
1787 if (size != entry_size)
1788 FAIL (ctx, g_strdup_printf ("ContantValue: Expected size %d but got %d", size, entry_size));
1792 if (ADD_IS_GREATER_OR_OVF (offset, size, blob.size))
1793 FAIL (ctx, g_strdup_printf ("ContantValue: Not enough room for constant, required %d but have %d", size, blob.size - offset));
1795 if (type == MONO_TYPE_CLASS && read32 (ctx->data + blob.offset + offset))
1796 FAIL (ctx, g_strdup_printf ("ContantValue: Type is class but value is not null"));
1800 #define FAT_HEADER_INVALID_FLAGS ~(0x3 | 0x8 | 0x10 | 0xF000)
1801 //only 0x01, 0x40 and 0x80 are allowed
1802 #define SECTION_HEADER_INVALID_FLAGS 0x3E
1805 is_valid_method_header (VerifyContext *ctx, guint32 rva)
1807 guint32 local_vars_tok, code_size, offset = mono_cli_rva_image_map (ctx->image, rva);
1809 guint16 fat_header = 0, size = 0, max_stack;
1810 const char *ptr = NULL, *end;
1812 if (offset == INVALID_ADDRESS)
1813 FAIL (ctx, g_strdup ("MethodHeader: Invalid RVA"));
1815 ptr = ctx->data + offset;
1816 end = ctx->data + ctx->size; /*no worries if it spawns multiple sections*/
1818 if (!safe_read8 (header, ptr, end))
1819 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for header"));
1821 switch (header & 0x3) {
1824 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid header type 0x%x", header & 0x3));
1827 if (ADDP_IS_GREATER_OR_OVF (ptr, header, end))
1828 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for method body. Required %d, but only %d is available", header, end - ptr));
1833 if (!safe_read16 (fat_header, ptr, end))
1834 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for fat header"));
1836 size = (fat_header >> 12) & 0xF;
1838 FAIL (ctx, g_strdup ("MethodHeader: header size must be 3"));
1840 if (!safe_read16 (max_stack, ptr, end))
1841 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for max stack"));
1843 if (!safe_read32 (code_size, ptr, end))
1844 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for code size"));
1846 if (!safe_read32 (local_vars_tok, ptr, end))
1847 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for local vars tok"));
1849 if (local_vars_tok) {
1850 if (((local_vars_tok >> 24) & 0xFF) != 0x11)
1851 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature table 0x%x", ((local_vars_tok >> 24) & 0xFF)));
1852 if ((local_vars_tok & 0xFFFFFF) > ctx->image->tables [MONO_TABLE_STANDALONESIG].rows)
1853 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature points to invalid row 0x%x", local_vars_tok & 0xFFFFFF));
1856 if (fat_header & FAT_HEADER_INVALID_FLAGS)
1857 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid fat signature flags %x", fat_header & FAT_HEADER_INVALID_FLAGS));
1859 if (ADDP_IS_GREATER_OR_OVF (ptr, code_size, end))
1860 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for code %d", code_size));
1862 if (!(fat_header & 0x08))
1868 guint32 section_header = 0, section_size = 0;
1871 ptr = dword_align (ptr);
1872 if (!safe_read32 (section_header, ptr, end))
1873 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for data section header"));
1875 if (section_header & SECTION_HEADER_INVALID_FLAGS)
1876 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section header flags 0x%x", section_header & SECTION_HEADER_INVALID_FLAGS));
1878 is_fat = (section_header & METHOD_HEADER_SECTION_FAT_FORMAT) != 0;
1879 section_size = (section_header >> 8) & (is_fat ? 0xFFFFFF : 0xFF);
1881 if (section_size < 4)
1882 FAIL (ctx, g_strdup_printf ("MethodHeader: Section size too small"));
1884 if (ADDP_IS_GREATER_OR_OVF (ptr, section_size - 4, end)) /*must be section_size -4 as ptr was incremented by safe_read32*/
1885 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section content %d", section_size));
1887 if (section_header & METHOD_HEADER_SECTION_EHTABLE) {
1888 guint32 i, clauses = (section_size - 4) / (is_fat ? 24 : 12);
1889 if (clauses * (is_fat ? 24 : 12) + 4 != section_size)
1890 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid EH section size %d, it's not of the proper size", section_size));
1892 /* only verify the class token is verified as the rest is done by the IL verifier*/
1893 for (i = 0; i < clauses; ++i) {
1894 guint32 class_token = 0;
1895 ptr += (is_fat ? 20 : 8);
1896 if (!safe_read32 (class_token, ptr, end))
1897 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section %d", i));
1898 if (!*ptr == MONO_EXCEPTION_CLAUSE_NONE && class_token) {
1899 guint table = mono_metadata_token_table (class_token);
1900 if (table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPESPEC)
1901 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token table %x", i, table));
1902 if (mono_metadata_token_index (class_token) > ctx->image->tables [table].rows)
1903 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token index %x", i, mono_metadata_token_index (class_token)));
1908 if (!(section_header & METHOD_HEADER_SECTION_MORE_SECTS))
1915 verify_module_table (VerifyContext *ctx)
1917 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
1918 guint32 data [MONO_MODULE_SIZE];
1920 if (table->rows != 1)
1921 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
1923 mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
1925 if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
1926 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
1928 if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
1929 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
1931 if (data [MONO_MODULE_ENC] != 0)
1932 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
1934 if (data [MONO_MODULE_ENCBASE] != 0)
1935 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
1939 verify_typeref_table (VerifyContext *ctx)
1941 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
1942 guint32 data [MONO_TYPEREF_SIZE];
1945 for (i = 0; i < table->rows; ++i) {
1946 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
1947 if (!is_valid_coded_index (ctx, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1948 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d coded index 0x%08x", i, data [MONO_TYPEREF_SCOPE]));
1950 if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1951 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", i));
1953 if (!data [MONO_TYPEREF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAME]))
1954 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d name token 0x%08x", i, data [MONO_TYPEREF_NAME]));
1956 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
1957 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d namespace token 0x%08x", i, data [MONO_TYPEREF_NAMESPACE]));
1961 /*bits 9,11,14,15,19,21,24-31 */
1962 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 14) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
1964 verify_typedef_table (VerifyContext *ctx)
1966 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
1967 guint32 data [MONO_TYPEDEF_SIZE];
1968 guint32 fieldlist = 1, methodlist = 1;
1971 if (table->rows == 0)
1972 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
1974 for (i = 0; i < table->rows; ++i) {
1975 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
1976 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
1977 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
1979 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
1980 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
1982 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
1983 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
1985 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
1986 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
1988 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
1989 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
1991 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
1992 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
1994 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
1995 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
1997 if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
1998 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
2000 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
2001 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));
2003 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
2004 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
2006 if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
2007 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
2009 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
2010 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));
2013 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
2014 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
2019 verify_typedef_table_full (VerifyContext *ctx)
2021 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2022 guint32 data [MONO_TYPEDEF_SIZE];
2025 if (table->rows == 0)
2026 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2028 for (i = 0; i < table->rows; ++i) {
2029 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2032 if (data [MONO_TYPEDEF_EXTENDS] != 0)
2033 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
2037 if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
2038 if (data [MONO_TYPEDEF_EXTENDS])
2039 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
2040 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
2041 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
2043 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
2044 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
2047 if (!(data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE)) {
2048 gboolean is_sys_obj = typedef_is_system_object (ctx, data);
2049 gboolean has_parent = get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]) != 0;
2053 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
2056 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
2064 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
2066 verify_field_table (VerifyContext *ctx)
2068 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2069 guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
2072 module_field_list = (guint32)-1;
2073 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2074 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2075 module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
2078 for (i = 0; i < table->rows; ++i) {
2079 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2080 flags = data [MONO_FIELD_FLAGS];
2082 if (flags & INVALID_FIELD_FLAG_BITS)
2083 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
2085 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)
2086 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
2088 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
2089 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
2091 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
2092 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
2094 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
2095 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
2097 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
2098 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
2099 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
2101 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
2102 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2103 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2105 if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
2106 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2107 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
2109 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
2110 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
2111 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2113 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
2114 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
2116 //TODO verify contant flag
2118 if (i + 1 < module_field_list) {
2119 guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
2120 if (!(flags & FIELD_ATTRIBUTE_STATIC))
2121 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
2122 if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
2123 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
2129 verify_field_table_full (VerifyContext *ctx)
2131 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2132 guint32 data [MONO_FIELD_SIZE];
2135 for (i = 0; i < table->rows; ++i) {
2136 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2138 if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
2139 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
2143 /*bits 6,8,9,10,11,13,14,15*/
2144 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 6) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
2146 verify_method_table (VerifyContext *ctx)
2148 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2149 guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
2150 guint32 paramlist = 1;
2151 gboolean is_ctor, is_cctor;
2155 module_method_list = (guint32)-1;
2156 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2157 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2158 module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
2161 for (i = 0; i < table->rows; ++i) {
2162 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2163 rva = data [MONO_METHOD_RVA];
2164 implflags = data [MONO_METHOD_IMPLFLAGS];
2165 flags = data [MONO_METHOD_FLAGS];
2166 access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
2167 code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
2170 if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
2171 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
2174 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
2176 if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
2177 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
2179 name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
2180 is_ctor = !strcmp (".ctor", name);
2181 is_cctor = !strcmp (".cctor", name);
2183 if ((is_ctor || is_cctor) &&
2184 search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
2185 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
2187 if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
2188 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
2190 if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
2191 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
2192 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
2193 if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
2194 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
2197 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
2198 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
2200 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
2201 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
2203 //XXX no checks against cas stuff 10,11,12,13)
2205 //TODO check iface with .ctor (15,16)
2207 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
2208 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
2210 if (i + 1 < module_method_list) {
2211 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2212 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
2213 if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
2214 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
2215 if (!(access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED || access == METHOD_ATTRIBUTE_PUBLIC || access == METHOD_ATTRIBUTE_PRIVATE))
2216 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public or Private", i));
2219 //TODO check valuetype for synchronized
2221 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
2222 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
2224 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && (flags & METHOD_ATTRIBUTE_VIRTUAL))
2225 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
2227 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
2228 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2229 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
2231 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
2232 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
2234 //TODO check signature contents
2237 if (flags & METHOD_ATTRIBUTE_ABSTRACT)
2238 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", i));
2239 if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
2240 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
2242 if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2243 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
2246 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2248 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
2249 if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
2250 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
2252 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
2253 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
2255 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
2256 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
2258 if (data [MONO_METHOD_PARAMLIST] == 0)
2259 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
2261 if (data [MONO_METHOD_PARAMLIST] < paramlist)
2262 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));
2264 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
2265 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
2267 paramlist = data [MONO_METHOD_PARAMLIST];
2273 verify_method_table_full (VerifyContext *ctx)
2275 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2276 guint32 data [MONO_METHOD_SIZE], rva;
2279 for (i = 0; i < table->rows; ++i) {
2280 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2281 rva = data [MONO_METHOD_RVA];
2283 if (rva && !is_valid_method_header (ctx, rva))
2284 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
2289 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
2291 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2292 guint32 row = *current_method;
2293 guint32 paramlist, tmp;
2296 paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
2297 while (row < table->rows) {
2298 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
2299 if (tmp > paramlist) {
2300 *current_method = row;
2301 return tmp - paramlist;
2306 /*no more methods, all params apply to the last one*/
2307 *current_method = table->rows;
2312 #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))
2314 verify_param_table (VerifyContext *ctx)
2316 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
2317 guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
2318 gboolean first_param = TRUE;
2321 if (ctx->image->tables [MONO_TABLE_METHOD].rows == 0) {
2322 if (table->rows > 0)
2323 ADD_ERROR (ctx, g_strdup ("Param table has rows while the method table has zero"));
2327 remaining_params = get_next_param_count (ctx, ¤t_method);
2329 for (i = 0; i < table->rows; ++i) {
2330 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
2331 flags = data [MONO_PARAM_FLAGS];
2333 if (flags & INVALID_PARAM_FLAGS_BITS)
2334 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
2336 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
2337 if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
2338 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
2340 if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
2341 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
2344 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)
2345 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
2347 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
2348 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
2350 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
2351 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
2353 first_param = FALSE;
2354 sequence = data [MONO_PARAM_SEQUENCE];
2355 if (--remaining_params == 0) {
2356 remaining_params = get_next_param_count (ctx, ¤t_method);
2363 verify_interfaceimpl_table (VerifyContext *ctx)
2365 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
2366 guint32 data [MONO_INTERFACEIMPL_SIZE];
2369 for (i = 0; i < table->rows; ++i) {
2370 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
2371 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2372 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2374 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2375 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
2377 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2378 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
2383 verify_memberref_table (VerifyContext *ctx)
2385 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2386 guint32 data [MONO_MEMBERREF_SIZE];
2389 for (i = 0; i < table->rows; ++i) {
2390 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2392 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2393 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
2395 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2396 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
2398 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
2399 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
2405 verify_memberref_table_full (VerifyContext *ctx)
2407 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2408 guint32 data [MONO_MEMBERREF_SIZE];
2411 for (i = 0; i < table->rows; ++i) {
2412 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2414 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
2415 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field 0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
2420 verify_constant_table (VerifyContext *ctx)
2422 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
2423 guint32 data [MONO_CONSTANT_SIZE], type;
2426 for (i = 0; i < table->rows; ++i) {
2427 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
2428 type = data [MONO_CONSTANT_TYPE];
2430 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
2431 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
2433 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2434 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
2436 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2437 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
2439 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
2440 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
2445 verify_cattr_table (VerifyContext *ctx)
2447 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2448 guint32 data [MONO_CUSTOM_ATTR_SIZE];
2451 for (i = 0; i < table->rows; ++i) {
2452 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2454 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
2455 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2457 if (!is_valid_coded_index (ctx, CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]))
2458 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2463 verify_cattr_table_full (VerifyContext *ctx)
2465 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2466 guint32 data [MONO_CUSTOM_ATTR_SIZE];
2469 for (i = 0; i < table->rows; ++i) {
2470 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2472 if (!is_vald_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
2473 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2478 verify_field_marshal_table (VerifyContext *ctx)
2480 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2481 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2484 for (i = 0; i < table->rows; ++i) {
2485 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2487 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2488 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
2490 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2491 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
2493 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
2494 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
2499 verify_field_marshal_table_full (VerifyContext *ctx)
2501 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2502 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2505 for (i = 0; i < table->rows; ++i) {
2506 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2508 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
2509 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2514 verify_decl_security_table (VerifyContext *ctx)
2516 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2517 guint32 data [MONO_DECL_SECURITY_SIZE];
2520 for (i = 0; i < table->rows; ++i) {
2521 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2523 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2524 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
2526 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2527 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
2529 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
2530 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
2535 verify_decl_security_table_full (VerifyContext *ctx)
2537 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2538 guint32 data [MONO_DECL_SECURITY_SIZE];
2541 for (i = 0; i < table->rows; ++i) {
2542 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2544 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
2545 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
2550 verify_class_layout_table (VerifyContext *ctx)
2552 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
2553 guint32 data [MONO_CLASS_LAYOUT_SIZE];
2556 for (i = 0; i < table->rows; ++i) {
2557 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
2559 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2560 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2562 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
2574 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
2580 verify_field_layout_table (VerifyContext *ctx)
2582 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
2583 guint32 data [MONO_FIELD_LAYOUT_SIZE];
2586 for (i = 0; i < table->rows; ++i) {
2587 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
2589 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2590 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
2595 verify_standalonesig_table_full (VerifyContext *ctx)
2597 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
2598 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
2601 for (i = 0; i < table->rows; ++i) {
2602 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
2604 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
2605 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
2610 verify_eventmap_table (VerifyContext *ctx)
2612 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
2613 guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
2616 for (i = 0; i < table->rows; ++i) {
2617 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
2619 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2620 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
2622 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
2623 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
2625 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
2629 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
2631 verify_event_table (VerifyContext *ctx)
2633 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
2634 guint32 data [MONO_EVENT_SIZE];
2637 for (i = 0; i < table->rows; ++i) {
2638 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
2640 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
2641 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
2643 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
2644 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
2646 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
2647 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
2652 verify_event_table_full (VerifyContext *ctx)
2654 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
2655 MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
2656 guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
2657 gboolean found_add, found_remove;
2660 for (i = 0; i < table->rows; ++i) {
2661 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
2663 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
2664 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
2666 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
2668 //first we move to the first row for this event
2670 if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
2674 //now move forward looking for AddOn and RemoveOn rows
2675 found_add = found_remove = FALSE;
2676 while (idx < sema_table->rows) {
2677 mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
2678 if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
2680 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
2682 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
2683 found_remove = TRUE;
2684 if (found_add && found_remove)
2690 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2692 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2697 verify_propertymap_table (VerifyContext *ctx)
2699 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
2700 guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
2703 for (i = 0; i < table->rows; ++i) {
2704 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
2706 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2707 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
2709 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
2710 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
2712 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
2716 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
2718 verify_property_table (VerifyContext *ctx)
2720 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
2721 guint32 data [MONO_PROPERTY_SIZE];
2724 for (i = 0; i < table->rows; ++i) {
2725 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
2727 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
2728 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
2730 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
2731 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
2733 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
2734 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
2736 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
2737 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
2738 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
2744 verify_methodimpl_table (VerifyContext *ctx)
2746 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
2747 guint32 data [MONO_METHODIMPL_SIZE];
2750 for (i = 0; i < table->rows; ++i) {
2751 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
2753 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2754 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2756 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2757 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2759 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2760 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2762 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2763 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2765 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2766 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2771 verify_moduleref_table (VerifyContext *ctx)
2773 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
2774 guint32 data [MONO_MODULEREF_SIZE];
2777 for (i = 0; i < table->rows; ++i) {
2778 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
2780 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
2781 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2786 verify_typespec_table_full (VerifyContext *ctx)
2788 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
2789 guint32 data [MONO_TYPESPEC_SIZE];
2792 for (i = 0; i < table->rows; ++i) {
2793 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
2795 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
2796 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
2800 #define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 6) | (1 << 8) | (1 << 9) | (1 << 10))
2802 verify_implmap_table (VerifyContext *ctx)
2804 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
2805 guint32 data [MONO_IMPLMAP_SIZE], cconv;
2808 for (i = 0; i < table->rows; ++i) {
2809 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
2811 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
2812 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
2814 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
2815 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
2816 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
2818 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2819 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
2821 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
2822 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
2824 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2825 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
2827 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
2828 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
2830 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULEREF].rows + 1)
2831 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
2836 verify_fieldrva_table (VerifyContext *ctx)
2838 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
2839 guint32 data [MONO_FIELD_RVA_SIZE];
2842 for (i = 0; i < table->rows; ++i) {
2843 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
2845 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
2846 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
2848 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2849 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
2853 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 8) | (1 << 14) | (1 << 15))
2855 verify_assembly_table (VerifyContext *ctx)
2857 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
2858 guint32 data [MONO_ASSEMBLY_SIZE], hash;
2861 if (table->rows > 1)
2862 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
2864 for (i = 0; i < table->rows; ++i) {
2865 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
2867 hash = data [MONO_ASSEMBLY_HASH_ALG];
2868 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
2869 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
2871 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
2872 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2874 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY]))
2875 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2877 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
2878 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
2880 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
2881 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
2885 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~(1)
2887 verify_assemblyref_table (VerifyContext *ctx)
2889 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
2890 guint32 data [MONO_ASSEMBLYREF_SIZE];
2893 for (i = 0; i < table->rows; ++i) {
2894 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
2896 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
2897 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
2899 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY]))
2900 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
2902 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
2903 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
2905 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
2906 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
2908 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE]))
2909 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
2913 #define INVALID_FILE_FLAGS_BITS ~(1)
2915 verify_file_table (VerifyContext *ctx)
2917 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
2918 guint32 data [MONO_FILE_SIZE];
2921 for (i = 0; i < table->rows; ++i) {
2922 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
2924 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
2925 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
2927 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
2928 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
2930 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE]))
2931 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
2935 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
2937 verify_exportedtype_table (VerifyContext *ctx)
2939 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
2940 guint32 data [MONO_EXP_TYPE_SIZE];
2943 for (i = 0; i < table->rows; ++i) {
2944 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
2946 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
2947 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
2949 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
2950 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
2952 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
2953 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
2955 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
2956 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
2958 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
2959 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
2961 /*nested type can't have a namespace*/
2962 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
2963 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
2967 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
2969 verify_manifest_resource_table (VerifyContext *ctx)
2971 MonoCLIImageInfo *iinfo = ctx->image->image_info;
2972 MonoCLIHeader *ch = &iinfo->cli_cli_header;
2973 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
2974 guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
2977 resources_size = ch->ch_resources.size;
2979 for (i = 0; i < table->rows; ++i) {
2980 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
2982 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
2983 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
2985 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
2986 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
2988 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
2989 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
2991 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
2992 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
2994 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
2995 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
2997 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
2998 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token table %08x", i, get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION])));
3000 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
3001 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
3003 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
3004 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
3009 verify_nested_class_table (VerifyContext *ctx)
3011 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3012 guint32 data [MONO_NESTED_CLASS_SIZE];
3015 for (i = 0; i < table->rows; ++i) {
3016 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
3018 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3019 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
3020 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3021 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3022 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
3023 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3027 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
3029 verify_generic_param_table (VerifyContext *ctx)
3031 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
3032 guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
3033 int i, param_number = 0;
3035 for (i = 0; i < table->rows; ++i) {
3036 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
3038 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
3039 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
3041 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
3042 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
3044 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
3045 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
3047 token = data [MONO_GENERICPARAM_OWNER];
3049 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
3050 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
3052 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
3053 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
3055 if (token != last_token) {
3060 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
3061 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));
3068 verify_method_spec_table (VerifyContext *ctx)
3070 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3071 guint32 data [MONO_METHODSPEC_SIZE];
3074 for (i = 0; i < table->rows; ++i) {
3075 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3077 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3078 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
3080 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3081 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
3086 verify_method_spec_table_full (VerifyContext *ctx)
3088 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3089 guint32 data [MONO_METHODSPEC_SIZE];
3092 for (i = 0; i < table->rows; ++i) {
3093 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3095 if (!is_valid_methodspec_blog (ctx, data [MONO_METHODSPEC_SIGNATURE]))
3096 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3101 verify_generic_param_constraint_table (VerifyContext *ctx)
3103 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
3104 guint32 data [MONO_GENPARCONSTRAINT_SIZE];
3107 for (i = 0; i < table->rows; ++i) {
3108 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
3110 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
3111 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_TABLE_GENERICPARAM]));
3113 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3114 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
3116 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3117 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
3122 verify_tables_data (VerifyContext *ctx)
3124 OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
3125 guint32 size = 0, tables_offset;
3128 for (i = 0; i < 0x2D; ++i) {
3129 MonoTableInfo *table = &ctx->image->tables [i];
3131 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
3132 if (tmp_size < size) {
3140 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
3142 tables_offset = ctx->image->tables_base - ctx->data;
3143 if (!bounds_check_offset (&tables_area, tables_offset, size))
3144 ADD_ERROR (ctx, g_strdup_printf ("Tables data require %d bytes but the only %d are available in the #~ stream", size, tables_area.size - (tables_offset - tables_area.offset)));
3146 verify_module_table (ctx);
3148 verify_typeref_table (ctx);
3150 verify_typedef_table (ctx);
3152 verify_field_table (ctx);
3154 verify_method_table (ctx);
3156 verify_param_table (ctx);
3158 verify_interfaceimpl_table (ctx);
3160 verify_memberref_table (ctx);
3162 verify_constant_table (ctx);
3164 verify_cattr_table (ctx);
3166 verify_field_marshal_table (ctx);
3168 verify_decl_security_table (ctx);
3170 verify_class_layout_table (ctx);
3172 verify_field_layout_table (ctx);
3174 verify_eventmap_table (ctx);
3176 verify_event_table (ctx);
3178 verify_propertymap_table (ctx);
3180 verify_property_table (ctx);
3182 verify_methodimpl_table (ctx);
3184 verify_moduleref_table (ctx);
3186 verify_implmap_table (ctx);
3188 verify_fieldrva_table (ctx);
3190 verify_assembly_table (ctx);
3192 verify_assemblyref_table (ctx);
3194 verify_file_table (ctx);
3196 verify_exportedtype_table (ctx);
3198 verify_manifest_resource_table (ctx);
3200 verify_nested_class_table (ctx);
3202 verify_generic_param_table (ctx);
3204 verify_method_spec_table (ctx);
3206 verify_generic_param_constraint_table (ctx);
3210 init_verify_context (VerifyContext *ctx, MonoImage *image, GSList **error_list)
3212 memset (ctx, 0, sizeof (VerifyContext));
3214 ctx->report_error = error_list != NULL;
3216 ctx->size = image->raw_data_len;
3217 ctx->data = image->raw_data;
3221 cleanup_context (VerifyContext *ctx, GSList **error_list)
3223 g_free (ctx->sections);
3225 *error_list = ctx->errors;
3227 mono_free_verify_list (ctx->errors);
3232 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3236 if (!mono_verifier_is_enabled_for_image (image))
3239 init_verify_context (&ctx, image, error_list);
3240 ctx.stage = STAGE_PE;
3242 verify_msdos_header (&ctx);
3244 verify_pe_header (&ctx);
3246 verify_pe_optional_header (&ctx);
3248 load_section_table (&ctx);
3250 load_data_directories (&ctx);
3252 verify_import_table (&ctx);
3254 /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
3255 verify_resources_table (&ctx);
3258 return cleanup_context (&ctx, error_list);
3262 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3266 if (!mono_verifier_is_enabled_for_image (image))
3269 init_verify_context (&ctx, image, error_list);
3270 ctx.stage = STAGE_CLI;
3272 verify_cli_header (&ctx);
3274 verify_metadata_header (&ctx);
3276 verify_tables_schema (&ctx);
3279 return cleanup_context (&ctx, error_list);
3284 * Verifies basic table constraints such as global table invariants (sorting, field monotonicity, etc).
3285 * Other verification checks are meant to be done lazily by the runtime. Those include:
3286 * blob items (signatures, method headers, custom attributes, etc)
3287 * type semantics related
3289 * stuff that should not block other pieces from running such as bad types/methods/fields/etc.
3291 * The whole idea is that if this succeed the runtime is free to play around safely but any complex
3292 * operation still need more checking.
3295 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3299 if (!mono_verifier_is_enabled_for_image (image))
3302 init_verify_context (&ctx, image, error_list);
3303 ctx.stage = STAGE_TABLES;
3305 verify_tables_data (&ctx);
3307 return cleanup_context (&ctx, error_list);
3312 * Verifies all other constraints.
3315 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3319 if (!mono_verifier_is_enabled_for_image (image))
3322 init_verify_context (&ctx, image, error_list);
3323 ctx.stage = STAGE_TABLES;
3325 verify_typedef_table_full (&ctx);
3327 verify_field_table_full (&ctx);
3329 verify_method_table_full (&ctx);
3331 verify_memberref_table_full (&ctx);
3333 verify_cattr_table_full (&ctx);
3335 verify_field_marshal_table_full (&ctx);
3337 verify_decl_security_table_full (&ctx);
3339 verify_standalonesig_table_full (&ctx);
3341 verify_event_table_full (&ctx);
3343 verify_typespec_table_full (&ctx);
3345 verify_method_spec_table_full (&ctx);
3348 return cleanup_context (&ctx, error_list);
3353 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3359 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3365 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3371 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3376 #endif /* DISABLE_VERIFIER */