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;
224 gboolean report_error;
227 DataDirectory data_directories [16];
228 guint32 section_count;
229 SectionHeader *sections;
231 OffsetAndSize metadata_streams [5]; //offset from begin of the image
234 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception) \
236 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
237 vinfo->info.status = __status; \
238 vinfo->info.message = ( __msg); \
239 vinfo->exception_type = (__exception); \
240 (__ctx)->errors = g_slist_prepend ((__ctx)->errors, vinfo); \
244 #define ADD_ERROR(__ctx, __msg) \
246 if ((__ctx)->report_error) \
247 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
248 (__ctx)->valid = 0; \
252 #define CHECK_STATE() do { if (!ctx.valid) goto cleanup; } while (0)
254 #define CHECK_ERROR() do { if (!ctx->valid) return; } while (0)
257 pe_signature_offset (VerifyContext *ctx)
259 return read32 (ctx->data + 0x3c);
263 pe_header_offset (VerifyContext *ctx)
265 return read32 (ctx->data + 0x3c) + 4;
269 bounds_check_virtual_address (VerifyContext *ctx, guint32 rva, guint32 size)
273 if (rva + size < rva) //overflow
276 if (ctx->stage > STAGE_PE) {
277 MonoCLIImageInfo *iinfo = ctx->image->image_info;
278 const int top = iinfo->cli_section_count;
279 MonoSectionTable *tables = iinfo->cli_section_tables;
282 for (i = 0; i < top; i++) {
283 guint32 base = tables->st_virtual_address;
284 guint32 end = base + tables->st_raw_data_size;
286 if (rva >= base && rva + size <= end)
289 /*if ((addr >= tables->st_virtual_address) &&
290 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
292 return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
302 for (i = 0; i < ctx->section_count; ++i) {
303 guint32 base = ctx->sections [i].baseRVA;
304 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
305 if (rva >= base && rva + size <= end)
312 bounds_check_datadir (DataDirectory *dir, guint32 offset, guint32 size)
314 if (dir->translated_offset > offset)
316 if (dir->size < size)
318 return offset + size <= dir->translated_offset + dir->size;
322 bounds_check_offset (OffsetAndSize *off, guint32 offset, guint32 size)
324 if (off->offset > offset)
327 if (off->size < size)
330 return offset + size <= off->offset + off->size;
334 translate_rva (VerifyContext *ctx, guint32 rva)
338 if (ctx->stage > STAGE_PE)
339 return mono_cli_rva_image_map (ctx->image, rva);
344 for (i = 0; i < ctx->section_count; ++i) {
345 guint32 base = ctx->sections [i].baseRVA;
346 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
347 if (rva >= base && rva <= end) {
348 guint32 res = (rva - base) + ctx->sections [i].baseOffset;
350 return res >= ctx->size ? INVALID_OFFSET : res;
354 return INVALID_OFFSET;
358 verify_msdos_header (VerifyContext *ctx)
362 ADD_ERROR (ctx, g_strdup ("Not enough space for the MS-DOS header"));
363 if (ctx->data [0] != 0x4d || ctx->data [1] != 0x5a)
364 ADD_ERROR (ctx, g_strdup ("Invalid MS-DOS watermark"));
365 lfanew = pe_signature_offset (ctx);
366 if (lfanew > ctx->size - 4)
367 ADD_ERROR (ctx, g_strdup ("MS-DOS lfanew offset points to outside of the file"));
371 verify_pe_header (VerifyContext *ctx)
373 guint32 offset = pe_signature_offset (ctx);
374 const char *pe_header = ctx->data + offset;
375 if (pe_header [0] != 'P' || pe_header [1] != 'E' ||pe_header [2] != 0 ||pe_header [3] != 0)
376 ADD_ERROR (ctx, g_strdup ("Invalid PE header watermark"));
380 if (offset > ctx->size - 20)
381 ADD_ERROR (ctx, g_strdup ("File with truncated pe header"));
382 if (read16 (pe_header) != 0x14c)
383 ADD_ERROR (ctx, g_strdup ("Invalid PE header Machine value"));
387 verify_pe_optional_header (VerifyContext *ctx)
389 guint32 offset = pe_header_offset (ctx);
390 guint32 header_size, file_alignment;
391 const char *pe_header = ctx->data + offset;
392 const char *pe_optional_header = pe_header + 20;
394 header_size = read16 (pe_header + 16);
397 if (header_size < 2) /*must be at least 2 or we won't be able to read magic*/
398 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
400 if (offset > ctx->size - header_size || header_size > ctx->size)
401 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
403 if (read16 (pe_optional_header) == 0x10b) {
404 if (header_size != 224)
405 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header size %d", header_size));
407 /* LAMESPEC MS plays around this value and ignore it during validation
408 if (read32 (pe_optional_header + 28) != 0x400000)
409 ADD_ERROR (ctx, g_strdup_printf ("Invalid Image base %x", read32 (pe_optional_header + 28)));*/
410 if (read32 (pe_optional_header + 32) != 0x2000)
411 ADD_ERROR (ctx, g_strdup_printf ("Invalid Section Aligmnent %x", read32 (pe_optional_header + 32)));
412 file_alignment = read32 (pe_optional_header + 36);
413 if (file_alignment != 0x200 && file_alignment != 0x1000)
414 ADD_ERROR (ctx, g_strdup_printf ("Invalid file Aligmnent %x", file_alignment));
415 /* All the junk in the middle is irrelevant, specially for mono. */
416 if (read32 (pe_optional_header + 92) > 0x10)
417 ADD_ERROR (ctx, g_strdup_printf ("Too many data directories %x", read32 (pe_optional_header + 92)));
419 if (read16 (pe_optional_header) == 0x20B)
420 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle PE32+"));
422 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header magic %d", read16 (pe_optional_header)));
427 load_section_table (VerifyContext *ctx)
430 SectionHeader *sections;
431 guint32 offset = pe_header_offset (ctx);
432 const char *ptr = ctx->data + offset;
433 guint16 num_sections = ctx->section_count = read16 (ptr + 2);
435 offset += 244;/*FIXME, this constant is different under PE32+*/
438 if (num_sections * 40 > ctx->size - offset)
439 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
441 sections = ctx->sections = g_new0 (SectionHeader, num_sections);
442 for (i = 0; i < num_sections; ++i) {
443 sections [i].size = read32 (ptr + 8);
444 sections [i].baseRVA = read32 (ptr + 12);
445 sections [i].baseOffset = read32 (ptr + 20);
446 sections [i].rellocationsRVA = read32 (ptr + 24);
447 sections [i].numberOfRelocations = read16 (ptr + 32);
451 ptr = ctx->data + offset; /*reset it to the beggining*/
452 for (i = 0; i < num_sections; ++i) {
453 guint32 raw_size, flags;
454 if (sections [i].baseOffset == 0)
455 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with intialized data only"));
456 if (sections [i].baseOffset >= ctx->size)
457 ADD_ERROR (ctx, g_strdup_printf ("Invalid PointerToRawData %x points beyond EOF", sections [i].baseOffset));
458 if (sections [i].size > ctx->size - sections [i].baseOffset)
459 ADD_ERROR (ctx, g_strdup ("Invalid VirtualSize points beyond EOF"));
461 raw_size = read32 (ptr + 16);
462 if (raw_size < sections [i].size)
463 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with SizeOfRawData < VirtualSize"));
465 if (raw_size > ctx->size - sections [i].baseOffset)
466 ADD_ERROR (ctx, g_strdup_printf ("Invalid SizeOfRawData %x points beyond EOF", raw_size));
468 if (sections [i].rellocationsRVA || sections [i].numberOfRelocations)
469 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't handle section relocation"));
471 flags = read32 (ptr + 36);
472 /*TODO 0xFE0000E0 is all flags from cil-coff.h OR'd. Make it a less magical number*/
473 if (flags == 0 || (flags & ~0xFE0000E0) != 0)
474 ADD_ERROR (ctx, g_strdup_printf ("Invalid section flags %x", flags));
481 is_valid_data_directory (int i)
483 /*LAMESPEC 4 == certificate 6 == debug, MS uses both*/
484 return i == 1 || i == 2 || i == 5 || i == 12 || i == 14 || i == 4 || i == 6;
488 load_data_directories (VerifyContext *ctx)
490 guint32 offset = pe_header_offset (ctx) + 116; /*FIXME, this constant is different under PE32+*/
491 const char *ptr = ctx->data + offset;
494 for (i = 0; i < 16; ++i) {
495 guint32 rva = read32 (ptr);
496 guint32 size = read32 (ptr + 4);
498 /*LAMESPEC the authenticode data directory format is different. We don't support CAS, so lets ignore for now.*/
499 if (i == CERTIFICATE_TABLE_IDX) {
503 if ((rva != 0 || size != 0) && !is_valid_data_directory (i))
504 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d", i));
506 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
507 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d rva/size pair %x/%x", i, rva, size));
509 ctx->data_directories [i].rva = rva;
510 ctx->data_directories [i].size = size;
511 ctx->data_directories [i].translated_offset = translate_rva (ctx, rva);
517 #define SIZE_OF_MSCOREE (sizeof ("mscoree.dll"))
519 #define SIZE_OF_CORMAIN (sizeof ("_CorExeMain"))
522 verify_hint_name_table (VerifyContext *ctx, guint32 import_rva, const char *table_name)
525 guint32 hint_table_rva;
527 import_rva = translate_rva (ctx, import_rva);
528 g_assert (import_rva != INVALID_OFFSET);
530 hint_table_rva = read32 (ctx->data + import_rva);
531 if (!bounds_check_virtual_address (ctx, hint_table_rva, SIZE_OF_CORMAIN + 2))
532 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint/Name rva %d for %s", hint_table_rva, table_name));
534 hint_table_rva = translate_rva (ctx, hint_table_rva);
535 g_assert (hint_table_rva != INVALID_OFFSET);
536 ptr = ctx->data + hint_table_rva + 2;
538 if (memcmp ("_CorExeMain", ptr, SIZE_OF_CORMAIN) && memcmp ("_CorDllMain", ptr, SIZE_OF_CORMAIN)) {
539 char name[SIZE_OF_CORMAIN];
540 memcpy (name, ptr, SIZE_OF_CORMAIN);
541 name [SIZE_OF_CORMAIN - 1] = 0;
542 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint / Name: '%s'", name));
547 verify_import_table (VerifyContext *ctx)
549 DataDirectory it = ctx->data_directories [IMPORT_TABLE_IDX];
550 guint32 offset = it.translated_offset;
551 const char *ptr = ctx->data + offset;
552 guint32 name_rva, ilt_rva, iat_rva;
554 g_assert (offset != INVALID_OFFSET);
557 ADD_ERROR (ctx, g_strdup_printf ("Import table size %d is smaller than 40", it.size));
559 ilt_rva = read32 (ptr);
560 if (!bounds_check_virtual_address (ctx, ilt_rva, 8))
561 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Lookup Table rva %x", ilt_rva));
563 name_rva = read32 (ptr + 12);
564 if (!bounds_check_virtual_address (ctx, name_rva, SIZE_OF_MSCOREE))
565 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name rva %x", name_rva));
567 iat_rva = read32 (ptr + 16);
568 if (!bounds_check_virtual_address (ctx, iat_rva, 8))
569 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Address Table rva %x", iat_rva));
571 if (iat_rva != ctx->data_directories [IAT_IDX].rva)
572 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));
574 name_rva = translate_rva (ctx, name_rva);
575 g_assert (name_rva != INVALID_OFFSET);
576 ptr = ctx->data + name_rva;
578 if (memcmp ("mscoree.dll", ptr, SIZE_OF_MSCOREE)) {
579 char name[SIZE_OF_MSCOREE];
580 memcpy (name, ptr, SIZE_OF_MSCOREE);
581 name [SIZE_OF_MSCOREE - 1] = 0;
582 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name: '%s'", name));
585 verify_hint_name_table (ctx, ilt_rva, "Import Lookup Table");
587 verify_hint_name_table (ctx, iat_rva, "Import Address Table");
591 verify_resources_table (VerifyContext *ctx)
593 DataDirectory it = ctx->data_directories [RESOURCE_TABLE_IDX];
595 guint16 named_entries, id_entries;
596 const char *ptr, *root, *end;
602 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));
604 offset = it.translated_offset;
605 root = ptr = ctx->data + offset;
606 end = root + it.size;
608 g_assert (offset != INVALID_OFFSET);
610 named_entries = read16 (ptr + 12);
611 id_entries = read16 (ptr + 14);
613 if ((named_entries + id_entries) * 8 + 16 > it.size)
614 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));
616 /* XXX at least one unmanaged resource is added due to a call to AssemblyBuilder::DefineVersionInfoResource ()
617 if (named_entries || id_entries)
618 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support full verification of PECOFF resources"));
622 /*----------nothing from here on can use data_directory---*/
625 get_data_dir (VerifyContext *ctx, int idx)
627 MonoCLIImageInfo *iinfo = ctx->image->image_info;
628 MonoPEDirEntry *entry= &iinfo->cli_header.datadir.pe_export_table;
632 res.rva = entry->rva;
633 res.size = entry->size;
634 res.translated_offset = translate_rva (ctx, res.rva);
639 verify_cli_header (VerifyContext *ctx)
641 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
647 ADD_ERROR (ctx, g_strdup_printf ("CLI header missing"));
650 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size in data directory %d must be 72", it.size));
652 offset = it.translated_offset;
653 ptr = ctx->data + offset;
655 g_assert (offset != INVALID_OFFSET);
657 if (read16 (ptr) != 72)
658 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size %d must be 72", read16 (ptr)));
660 if (!bounds_check_virtual_address (ctx, read32 (ptr + 8), read32 (ptr + 12)))
661 ADD_ERROR (ctx, g_strdup_printf ("Invalid medatata section rva/size pair %x/%x", read32 (ptr + 8), read32 (ptr + 12)));
664 if (!read32 (ptr + 8) || !read32 (ptr + 12))
665 ADD_ERROR (ctx, g_strdup_printf ("Missing medatata section in the CLI header"));
667 if ((read32 (ptr + 16) & ~0x0001000B) != 0)
668 ADD_ERROR (ctx, g_strdup_printf ("Invalid CLI header flags"));
671 for (i = 0; i < 6; ++i) {
672 guint32 rva = read32 (ptr);
673 guint32 size = read32 (ptr + 4);
675 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
676 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli section %i rva/size pair %x/%x", i, rva, size));
681 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't support cli header section %d", i));
686 pad4 (guint32 offset)
688 if (offset & 0x3) //pad to the next 4 byte boundary
689 offset = (offset & ~0x3) + 4;
694 verify_metadata_header (VerifyContext *ctx)
697 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
701 offset = it.translated_offset;
702 ptr = ctx->data + offset;
703 g_assert (offset != INVALID_OFFSET);
705 //build a directory entry for the metadata root
707 it.rva = read32 (ptr);
709 it.size = read32 (ptr);
710 it.translated_offset = offset = translate_rva (ctx, it.rva);
712 ptr = ctx->data + offset;
713 g_assert (offset != INVALID_OFFSET);
716 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small %d (at least 20 bytes required for initial decoding)", it.size));
718 if (read32 (ptr) != 0x424A5342)
719 ADD_ERROR (ctx, g_strdup_printf ("Invalid metadata signature, expected 0x424A5342 but got %08x", read32 (ptr)));
721 offset = pad4 (offset + 16 + read32 (ptr + 12));
723 if (!bounds_check_datadir (&it, offset, 4))
724 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));
726 ptr = ctx->data + offset; //move to streams header
728 if (read16 (ptr + 2) < 3)
729 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section must have at least 3 streams (#~, #GUID and #Blob"));
734 for (i = 0; i < 5; ++i) {
735 guint32 stream_off, stream_size;
736 int string_size, stream_idx;
738 if (!bounds_check_datadir (&it, offset, 8))
739 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));
741 stream_off = it.translated_offset + read32 (ptr);
742 stream_size = read32 (ptr + 4);
744 if (!bounds_check_datadir (&it, stream_off, stream_size))
745 ADD_ERROR (ctx, g_strdup_printf ("Invalid stream header %d offset/size pair %x/%x", 0, stream_off, stream_size));
750 for (string_size = 0; string_size < 32; ++string_size) {
751 if (!bounds_check_datadir (&it, offset++, 1))
752 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small to decode stream header %d name", i));
753 if (!ptr [string_size])
757 if (ptr [string_size])
758 ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d name larger than 32 bytes", i));
760 if (!strncmp ("#Strings", ptr, 9))
761 stream_idx = STRINGS_STREAM;
762 else if (!strncmp ("#US", ptr, 4))
763 stream_idx = USER_STRINGS_STREAM;
764 else if (!strncmp ("#Blob", ptr, 6))
765 stream_idx = BLOB_STREAM;
766 else if (!strncmp ("#GUID", ptr, 6))
767 stream_idx = GUID_STREAM;
768 else if (!strncmp ("#~", ptr, 3))
769 stream_idx = TILDE_STREAM;
771 ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d invalid name %s", i, ptr));
773 if (ctx->metadata_streams [stream_idx].offset != 0)
774 ADD_ERROR (ctx, g_strdup_printf ("Duplicated metadata stream header %s", ptr));
776 ctx->metadata_streams [stream_idx].offset = stream_off;
777 ctx->metadata_streams [stream_idx].size = stream_size;
779 offset = pad4 (offset);
780 ptr = ctx->data + offset;
783 if (!ctx->metadata_streams [TILDE_STREAM].size)
784 ADD_ERROR (ctx, g_strdup_printf ("Metadata #~ stream missing"));
785 if (!ctx->metadata_streams [GUID_STREAM].size)
786 ADD_ERROR (ctx, g_strdup_printf ("Metadata guid stream missing"));
787 if (!ctx->metadata_streams [BLOB_STREAM].size)
788 ADD_ERROR (ctx, g_strdup_printf ("Metadata blob stream missing"));
793 verify_tables_schema (VerifyContext *ctx)
795 OffsetAndSize tables_area = ctx->metadata_streams [TILDE_STREAM];
796 unsigned offset = tables_area.offset;
797 const char *ptr = ctx->data + offset;
798 guint64 valid_tables;
802 //printf ("tables_area size %d offset %x %s\n", tables_area.size, tables_area.offset, ctx->image->name);
803 if (tables_area.size < 24)
804 ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for initial decoding (requires 24 bytes)", tables_area.size));
806 //printf ("ptr %x %x\n", ptr[4], ptr[5]);
807 if (ptr [4] != 2 && ptr [4] != 1)
808 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata major version %d, expected 2", ptr [4]));
810 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata minor version %d, expected 0", ptr [5]));
812 if ((ptr [6] & ~0x7) != 0)
813 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]));
815 valid_tables = read64 (ptr + 8);
817 for (i = 0; i < 64; ++i) {
818 if (!(valid_tables & ((guint64)1 << i)))
821 /*MS Extensions: 0x3 0x5 0x7 0x13 0x16
822 Unused: 0x1E 0x1F 0x2D-0x3F
823 We don't care about the MS extensions.*/
824 if (i == 0x3 || i == 0x5 || i == 0x7 || i == 0x13 || i == 0x16)
825 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifies doesn't support MS specific table %x", i));
826 if (i == 0x1E || i == 0x1F || i >= 0x2D)
827 ADD_ERROR (ctx, g_strdup_printf ("Invalid table %x", i));
831 if (tables_area.size < 24 + count * 4)
832 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));
835 for (i = 0; i < 64; ++i) {
836 if (valid_tables & ((guint64)1 << i)) {
837 guint32 row_count = read32 (ptr);
838 if (row_count > (1 << 24) - 1)
839 ADD_ERROR (ctx, g_strdup_printf ("Invalid Table %d row count: %d. Mono only supports 16777215 rows", i, row_count));
845 /*----------nothing from here on can use data_directory or metadata_streams ---*/
848 get_col_offset (VerifyContext *ctx, int table, int column)
850 guint32 bitfield = ctx->image->tables [table].size_bitfield;
854 offset += mono_metadata_table_size (bitfield, column);
860 get_col_size (VerifyContext *ctx, int table, int column)
862 return mono_metadata_table_size (ctx->image->tables [table].size_bitfield, column);
866 get_metadata_stream (VerifyContext *ctx, MonoStreamHeader *header)
869 res.offset = header->data - ctx->data;
870 res.size = header->size;
876 is_valid_string_full (VerifyContext *ctx, guint32 offset, gboolean allow_empty)
878 OffsetAndSize strings = get_metadata_stream (ctx, &ctx->image->heap_strings);
880 const char *data = ctx->data + strings.offset;
882 if (offset >= strings.size)
884 if (data + offset < data) //FIXME, use a generalized and smart unsigned add with overflow check and fix the whole thing
887 if (!mono_utf8_validate_and_len_with_bounds (data + offset, strings.size - offset, &length, NULL))
889 return allow_empty || length > 0;
893 is_valid_string (VerifyContext *ctx, guint32 offset)
895 return is_valid_string_full (ctx, offset, TRUE);
899 is_valid_non_empty_string (VerifyContext *ctx, guint32 offset)
901 return is_valid_string_full (ctx, offset, FALSE);
905 is_valid_guid (VerifyContext *ctx, guint32 offset)
907 OffsetAndSize guids = get_metadata_stream (ctx, &ctx->image->heap_guid);
908 return guids.size >= 8 && guids.size - 8 >= offset;
912 get_coded_index_token (int token_kind, guint32 coded_token)
914 guint32 bits = coded_index_desc [token_kind];
915 return coded_token >> bits;
919 get_coded_index_table (int kind, guint32 coded_token)
921 guint32 idx, bits = coded_index_desc [kind];
923 idx = coded_token & ((1 << bits) - 1);
924 return coded_index_desc [kind + idx];
928 make_coded_token (int kind, guint32 table, guint32 table_idx)
930 guint32 bits = coded_index_desc [kind++];
931 guint32 tables = coded_index_desc [kind++];
933 for (i = 0; i < tables; ++i) {
934 if (coded_index_desc [kind++] == table)
935 return ((table_idx + 1) << bits) | i;
937 g_assert_not_reached ();
942 is_valid_coded_index (VerifyContext *ctx, int token_kind, guint32 coded_token)
944 guint32 bits = coded_index_desc [token_kind++];
945 guint32 table_count = coded_index_desc [token_kind++];
946 guint32 table = coded_token & ((1 << bits) - 1);
947 guint32 token = coded_token >> bits;
949 if (table >= table_count)
952 /*token_kind points to the first table idx*/
953 table = coded_index_desc [token_kind + table];
955 if (table == INVALID_TABLE)
957 return token <= ctx->image->tables [table].rows;
964 MonoTableInfo *table;
968 token_locator (const void *a, const void *b)
970 RowLocator *loc = (RowLocator *)a;
971 unsigned const char *row = (unsigned const char *)b;
972 guint32 token = loc->col_size == 2 ? read16 (row + loc->col_offset) : read32 (row + loc->col_offset);
974 VERIFIER_DEBUG ( printf ("\tfound token %x at idx %d\n", token, ((const char*)row - loc->table->base) / loc->table->row_size) );
975 return (int)loc->token - (int)token;
979 search_sorted_table (VerifyContext *ctx, int table, int column, guint32 coded_token)
981 MonoTableInfo *tinfo = &ctx->image->tables [table];
983 const char *res, *base;
984 locator.token = coded_token;
985 locator.col_offset = get_col_offset (ctx, table, column);
986 locator.col_size = get_col_size (ctx, table, column);
987 locator.table = tinfo;
991 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) );
992 res = bsearch (&locator, base, tinfo->rows, tinfo->row_size, token_locator);
996 return (res - base) / tinfo->row_size;
999 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1001 get_string_ptr (VerifyContext *ctx, guint offset)
1003 return ctx->image->heap_strings.data + offset;
1006 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1008 string_cmp (VerifyContext *ctx, const char *str, guint offset)
1011 return strcmp (str, "");
1013 return strcmp (str, get_string_ptr (ctx, offset));
1017 typedef_is_system_object (VerifyContext *ctx, guint32 *data)
1019 return ctx->is_corlib && !string_cmp (ctx, "System", data [MONO_TYPEDEF_NAME]) && !string_cmp (ctx, "Object", data [MONO_TYPEDEF_NAMESPACE]);
1023 decode_value (const char *_ptr, guint32 available, guint32 *value, guint32 *size)
1026 const unsigned char *ptr = (const unsigned char *)_ptr;
1034 if ((b & 0x80) == 0) {
1037 } else if ((b & 0x40) == 0) {
1041 *value = ((b & 0x3f) << 8 | ptr [1]);
1046 *value = ((b & 0x1f) << 24) |
1056 decode_signature_header (VerifyContext *ctx, guint32 offset, int *size, const char **first_byte)
1058 MonoStreamHeader blob = ctx->image->heap_blob;
1059 guint32 value, enc_size;
1061 if (offset >= blob.size)
1064 if (!decode_value (blob.data + offset, blob.size - offset, &value, &enc_size))
1067 if (offset + enc_size + value < offset)
1070 if (offset + enc_size + value >= blob.size)
1074 *first_byte = blob.data + offset + enc_size;
1079 safe_read (const char **_ptr, const char *limit, void *dest, int size)
1081 const char *ptr = *_ptr;
1082 if (ptr + size >= limit)
1086 *((guint8*)dest) = *((guint8*)ptr);
1090 *((guint16*)dest) = *((guint16*)ptr);
1094 *((guint32*)dest) = *((guint32*)ptr);
1102 #define safe_read8(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 1)
1103 #define safe_read16(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 2)
1104 #define safe_read32(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 4)
1107 is_valid_field_signature (VerifyContext *ctx, guint32 offset)
1109 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1110 //TODO do proper verification
1111 return blob.size >= 2 && blob.size - 2 >= offset;
1115 is_valid_method_signature (VerifyContext *ctx, guint32 offset)
1117 int size = 0, cconv = 0;
1118 const char *ptr = NULL, *end;
1119 if (!decode_signature_header (ctx, offset, &size, &ptr))
1123 if (!safe_read8 (cconv, ptr, end))
1137 is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
1139 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1140 //TODO do proper verification
1141 return blob.size >= 2 && blob.size - 2 >= offset;
1145 is_vald_cattr_blob (VerifyContext *ctx, guint32 offset)
1147 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1148 //TODO do proper verification
1149 return blob.size >= 1 && blob.size - 1 >= offset;
1153 is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
1155 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1156 //TODO do proper verification
1157 return blob.size >= 1 && blob.size - 1 >= offset;
1161 is_valid_permission_set (VerifyContext *ctx, guint32 offset)
1163 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1164 //TODO do proper verification
1165 return blob.size >= 1 && blob.size - 1 >= offset;
1169 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
1171 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1172 //TODO do proper verification
1173 return blob.size >= 1 && blob.size - 1 >= offset;
1177 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
1179 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1180 //TODO do proper verification
1181 return offset > 0 && blob.size >= 1 && blob.size - 1 >= offset;
1185 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
1187 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1188 //TODO do proper verification
1189 return offset > 0 && blob.size >= 1 && blob.size - 1 >= offset;
1193 is_valid_methodspec_blog (VerifyContext *ctx, guint32 offset)
1195 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1196 //TODO do proper verification
1197 return offset > 0 && blob.size >= 1 && blob.size - 1 >= offset;
1201 is_valid_blob_object (VerifyContext *ctx, guint32 offset)
1203 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1204 guint32 entry_size, bytes;
1206 if (blob.size < offset) {
1211 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1214 if (offset + entry_size + bytes < offset)
1217 return blob.size >= offset + entry_size + bytes;
1221 is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
1223 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1224 guint32 size, entry_size, bytes;
1226 if (blob.size < offset) {
1232 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1235 if (type == MONO_TYPE_STRING) {
1236 //String is encoded as: compressed_int:len len *chars
1239 if (offset > offset + entry_size * 2) //overflow
1241 offset += offset + entry_size * 2;
1242 return offset <= blob.size;
1246 case MONO_TYPE_BOOLEAN:
1251 case MONO_TYPE_CHAR:
1259 case MONO_TYPE_CLASS:
1269 g_assert_not_reached ();
1272 if (size != entry_size)
1276 if(offset > offset + size) //overflow
1279 if (offset + size > blob.size)
1282 if (type == MONO_TYPE_CLASS && read32 (ctx->data + offset))
1288 is_valid_method_header (VerifyContext *ctx, guint32 rva)
1290 //TODO do proper method header validation
1291 return mono_cli_rva_image_map (ctx->image, rva) != INVALID_ADDRESS;
1295 verify_module_table (VerifyContext *ctx)
1297 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
1298 guint32 data [MONO_MODULE_SIZE];
1300 if (table->rows != 1)
1301 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
1303 mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
1305 if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
1306 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
1308 if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
1309 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
1311 if (data [MONO_MODULE_ENC] != 0)
1312 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
1314 if (data [MONO_MODULE_ENCBASE] != 0)
1315 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
1319 verify_typeref_table (VerifyContext *ctx)
1321 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
1322 guint32 data [MONO_TYPEREF_SIZE];
1325 for (i = 0; i < table->rows; ++i) {
1326 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
1327 if (!is_valid_coded_index (ctx, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1328 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d coded index 0x%08x", i, data [MONO_TYPEREF_SCOPE]));
1330 if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1331 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", i));
1333 if (!data [MONO_TYPEREF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAME]))
1334 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d name token 0x%08x", i, data [MONO_TYPEREF_NAME]));
1336 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
1337 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d namespace token 0x%08x", i, data [MONO_TYPEREF_NAMESPACE]));
1341 /*bits 9,11,14,15,19,21,24-31 */
1342 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 14) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
1344 verify_typedef_table (VerifyContext *ctx)
1346 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
1347 guint32 data [MONO_TYPEDEF_SIZE];
1348 guint32 fieldlist = 1, methodlist = 1;
1351 if (table->rows == 0)
1352 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
1354 for (i = 0; i < table->rows; ++i) {
1355 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
1356 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
1357 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
1359 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
1360 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
1362 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
1363 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
1365 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
1366 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
1368 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
1369 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
1371 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
1372 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
1375 if (data [MONO_TYPEDEF_EXTENDS] != 0)
1376 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
1378 if (typedef_is_system_object (ctx, data) && data [MONO_TYPEDEF_EXTENDS] != 0)
1379 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
1381 if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
1382 if (data [MONO_TYPEDEF_EXTENDS])
1383 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
1384 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
1385 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
1387 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
1388 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
1390 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
1391 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
1395 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
1396 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
1398 if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
1399 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
1401 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
1402 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));
1404 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
1405 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
1407 if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
1408 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
1410 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
1411 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));
1414 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
1415 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
1420 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
1422 verify_field_table (VerifyContext *ctx)
1424 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
1425 guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
1428 module_field_list = (guint32)-1;
1429 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
1430 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
1431 module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
1434 for (i = 0; i < table->rows; ++i) {
1435 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
1436 flags = data [MONO_FIELD_FLAGS];
1438 if (flags & INVALID_FIELD_FLAG_BITS)
1439 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
1441 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)
1442 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
1444 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
1445 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
1447 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
1448 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
1450 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
1451 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
1453 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
1454 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
1455 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
1457 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
1458 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
1459 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
1461 if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
1462 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
1463 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
1465 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
1466 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
1467 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
1469 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
1470 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
1472 //TODO verify contant flag
1473 if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
1474 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
1476 if (i + 1 < module_field_list) {
1477 guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
1478 if (!(flags & FIELD_ATTRIBUTE_STATIC))
1479 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
1480 if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
1481 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
1486 /*bits 6,8,9,10,11,13,14,15*/
1487 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 6) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
1489 verify_method_table (VerifyContext *ctx)
1491 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
1492 guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
1493 guint32 paramlist = 1;
1494 gboolean is_ctor, is_cctor;
1498 module_method_list = (guint32)-1;
1499 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
1500 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
1501 module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
1504 for (i = 0; i < table->rows; ++i) {
1505 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
1506 rva = data [MONO_METHOD_RVA];
1507 implflags = data [MONO_METHOD_IMPLFLAGS];
1508 flags = data [MONO_METHOD_FLAGS];
1509 access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
1510 code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
1513 if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
1514 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
1517 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
1519 if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
1520 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
1522 name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
1523 is_ctor = !strcmp (".ctor", name);
1524 is_cctor = !strcmp (".cctor", name);
1526 if ((is_ctor || is_cctor) &&
1527 search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
1528 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
1530 if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
1531 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
1533 if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
1534 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
1535 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
1536 if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
1537 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
1540 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
1541 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
1543 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
1544 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
1546 //XXX no checks against cas stuff 10,11,12,13)
1548 //TODO check iface with .ctor (15,16)
1550 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
1551 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token %08x", i, data [MONO_METHOD_SIGNATURE]));
1553 if (i + 1 < module_method_list) {
1554 if (!(flags & METHOD_ATTRIBUTE_STATIC))
1555 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
1556 if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
1557 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
1558 if (!(access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED || access == METHOD_ATTRIBUTE_PUBLIC || access == METHOD_ATTRIBUTE_PRIVATE))
1559 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public or Private", i));
1562 //TODO check valuetype for synchronized
1564 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
1565 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
1567 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && (flags & METHOD_ATTRIBUTE_VIRTUAL))
1568 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
1570 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
1571 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
1572 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
1574 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
1575 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
1577 //TODO check signature contents
1580 if (flags & METHOD_ATTRIBUTE_ABSTRACT)
1581 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", i));
1582 if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
1583 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
1584 if (!is_valid_method_header (ctx, rva))
1585 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
1587 if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
1588 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
1591 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
1593 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
1594 if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
1595 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
1597 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
1598 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
1600 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
1601 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
1603 if (data [MONO_METHOD_PARAMLIST] == 0)
1604 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
1606 if (data [MONO_METHOD_PARAMLIST] < paramlist)
1607 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));
1609 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
1610 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
1612 paramlist = data [MONO_METHOD_PARAMLIST];
1618 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
1620 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
1621 guint32 row = *current_method;
1622 guint32 paramlist, tmp;
1625 paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
1626 while (row < table->rows) {
1627 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
1628 if (tmp > paramlist) {
1629 *current_method = row;
1630 return tmp - paramlist;
1635 /*no more methods, all params apply to the last one*/
1636 *current_method = table->rows;
1641 #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))
1643 verify_param_table (VerifyContext *ctx)
1645 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
1646 guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
1647 gboolean first_param = TRUE;
1650 remaining_params = get_next_param_count (ctx, ¤t_method);
1652 for (i = 0; i < table->rows; ++i) {
1653 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
1654 flags = data [MONO_PARAM_FLAGS];
1656 if (flags & INVALID_PARAM_FLAGS_BITS)
1657 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
1659 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
1660 if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
1661 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
1663 if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
1664 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
1667 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)
1668 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
1670 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
1671 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
1673 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
1674 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
1676 first_param = FALSE;
1677 sequence = data [MONO_PARAM_SEQUENCE];
1678 if (--remaining_params == 0) {
1679 remaining_params = get_next_param_count (ctx, ¤t_method);
1686 verify_interfaceimpl_table (VerifyContext *ctx)
1688 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
1689 guint32 data [MONO_INTERFACEIMPL_SIZE];
1692 for (i = 0; i < table->rows; ++i) {
1693 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
1694 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
1695 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
1697 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
1698 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
1700 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
1701 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
1706 verify_memberref_table (VerifyContext *ctx)
1708 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
1709 guint32 data [MONO_MEMBERREF_SIZE];
1712 for (i = 0; i < table->rows; ++i) {
1713 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
1715 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
1716 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
1718 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
1719 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
1721 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
1722 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
1724 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
1725 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field 0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
1730 verify_constant_table (VerifyContext *ctx)
1732 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
1733 guint32 data [MONO_CONSTANT_SIZE], type;
1736 for (i = 0; i < table->rows; ++i) {
1737 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
1738 type = data [MONO_CONSTANT_TYPE];
1740 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
1741 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
1743 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
1744 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
1746 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
1747 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
1749 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
1750 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
1755 verify_cattr_table (VerifyContext *ctx)
1757 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1758 guint32 data [MONO_CUSTOM_ATTR_SIZE];
1761 for (i = 0; i < table->rows; ++i) {
1762 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
1764 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
1765 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
1767 if (!is_valid_coded_index (ctx, CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]))
1768 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
1770 if (!is_vald_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
1771 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
1777 verify_field_marshal_table (VerifyContext *ctx)
1779 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
1780 guint32 data [MONO_FIELD_MARSHAL_SIZE];
1783 for (i = 0; i < table->rows; ++i) {
1784 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
1786 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
1787 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
1789 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
1790 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
1792 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
1793 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
1795 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
1796 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
1802 verify_decl_security_table (VerifyContext *ctx)
1804 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
1805 guint32 data [MONO_DECL_SECURITY_SIZE];
1808 for (i = 0; i < table->rows; ++i) {
1809 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
1811 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
1812 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
1814 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
1815 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
1817 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
1818 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
1820 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
1821 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
1827 verify_class_layout_table (VerifyContext *ctx)
1829 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
1830 guint32 data [MONO_CLASS_LAYOUT_SIZE];
1833 for (i = 0; i < table->rows; ++i) {
1834 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
1836 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
1837 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
1839 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
1851 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
1857 verify_field_layout_table (VerifyContext *ctx)
1859 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
1860 guint32 data [MONO_FIELD_LAYOUT_SIZE];
1863 for (i = 0; i < table->rows; ++i) {
1864 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
1866 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
1867 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
1872 verify_standalonesig_table (VerifyContext *ctx)
1874 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
1875 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
1878 for (i = 0; i < table->rows; ++i) {
1879 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
1881 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
1882 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
1887 verify_eventmap_table (VerifyContext *ctx)
1889 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
1890 guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
1893 for (i = 0; i < table->rows; ++i) {
1894 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
1896 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
1897 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
1899 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
1900 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
1902 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
1906 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
1908 verify_event_table (VerifyContext *ctx)
1910 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
1911 MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
1912 guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
1913 gboolean found_add, found_remove;
1916 for (i = 0; i < table->rows; ++i) {
1917 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
1919 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
1920 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
1922 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
1923 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
1925 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
1926 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
1928 //check for Add and Remove
1929 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
1930 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
1932 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
1934 //first we move to the first row for this event
1936 if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
1940 //now move forward looking for AddOn and RemoveOn rows
1941 found_add = found_remove = FALSE;
1942 while (idx < sema_table->rows) {
1943 mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
1944 if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
1946 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
1948 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
1949 found_remove = TRUE;
1950 if (found_add && found_remove)
1956 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
1958 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
1963 verify_propertymap_table (VerifyContext *ctx)
1965 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
1966 guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
1969 for (i = 0; i < table->rows; ++i) {
1970 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
1972 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
1973 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
1975 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
1976 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
1978 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
1982 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
1984 verify_property_table (VerifyContext *ctx)
1986 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
1987 guint32 data [MONO_PROPERTY_SIZE];
1990 for (i = 0; i < table->rows; ++i) {
1991 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
1993 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
1994 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
1996 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
1997 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
1999 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
2000 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
2002 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
2003 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
2004 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
2010 verify_methodimpl_table (VerifyContext *ctx)
2012 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
2013 guint32 data [MONO_METHODIMPL_SIZE];
2016 for (i = 0; i < table->rows; ++i) {
2017 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
2019 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2020 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2022 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2023 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2025 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2026 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2028 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2029 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2031 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2032 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2037 verify_moduleref_table (VerifyContext *ctx)
2039 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
2040 guint32 data [MONO_MODULEREF_SIZE];
2043 for (i = 0; i < table->rows; ++i) {
2044 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
2046 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
2047 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2052 verify_typespec_table (VerifyContext *ctx)
2054 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
2055 guint32 data [MONO_TYPESPEC_SIZE];
2058 for (i = 0; i < table->rows; ++i) {
2059 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
2061 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
2062 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
2066 #define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10))
2068 verify_implmap_table (VerifyContext *ctx)
2070 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
2071 guint32 data [MONO_IMPLMAP_SIZE], cconv;
2074 for (i = 0; i < table->rows; ++i) {
2075 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
2077 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
2078 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
2080 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
2081 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
2082 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
2084 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2085 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
2087 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
2088 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
2090 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2091 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
2093 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
2094 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
2096 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULE].rows + 1)
2097 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
2102 verify_fieldrva_table (VerifyContext *ctx)
2104 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
2105 guint32 data [MONO_FIELD_RVA_SIZE];
2108 for (i = 0; i < table->rows; ++i) {
2109 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
2111 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
2112 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
2114 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2115 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
2119 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 8) | (1 << 14) | (1 << 15))
2121 verify_assembly_table (VerifyContext *ctx)
2123 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
2124 guint32 data [MONO_ASSEMBLY_SIZE], hash;
2127 if (table->rows > 1)
2128 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
2130 for (i = 0; i < table->rows; ++i) {
2131 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
2133 hash = data [MONO_ASSEMBLY_HASH_ALG];
2134 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
2135 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
2137 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
2138 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2140 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY]))
2141 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2143 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
2144 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
2146 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
2147 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
2151 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~(1)
2153 verify_assemblyref_table (VerifyContext *ctx)
2155 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
2156 guint32 data [MONO_ASSEMBLYREF_SIZE];
2159 for (i = 0; i < table->rows; ++i) {
2160 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
2162 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
2163 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
2165 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY]))
2166 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
2168 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
2169 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
2171 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
2172 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
2174 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE]))
2175 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
2179 #define INVALID_FILE_FLAGS_BITS ~(1)
2181 verify_file_table (VerifyContext *ctx)
2183 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
2184 guint32 data [MONO_FILE_SIZE];
2187 for (i = 0; i < table->rows; ++i) {
2188 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
2190 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
2191 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
2193 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
2194 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
2196 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE]))
2197 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
2201 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
2203 verify_exportedtype_table (VerifyContext *ctx)
2205 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
2206 guint32 data [MONO_EXP_TYPE_SIZE];
2209 for (i = 0; i < table->rows; ++i) {
2210 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
2212 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
2213 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
2215 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
2216 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
2218 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
2219 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
2221 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
2222 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
2224 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
2225 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
2227 /*nested type can't have a namespace*/
2228 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
2229 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
2233 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
2235 verify_manifest_resource_table (VerifyContext *ctx)
2237 MonoCLIImageInfo *iinfo = ctx->image->image_info;
2238 MonoCLIHeader *ch = &iinfo->cli_cli_header;
2239 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
2240 guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
2243 resources_size = ch->ch_resources.size;
2245 for (i = 0; i < table->rows; ++i) {
2246 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
2248 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
2249 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
2251 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
2252 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
2254 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
2255 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
2257 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
2258 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
2260 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
2261 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
2263 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
2264 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])));
2266 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
2267 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
2269 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
2270 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
2275 verify_nested_class_table (VerifyContext *ctx)
2277 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
2278 guint32 data [MONO_NESTED_CLASS_SIZE];
2281 for (i = 0; i < table->rows; ++i) {
2282 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
2284 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2285 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
2286 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2287 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
2288 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
2289 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
2293 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
2295 verify_generic_param_table (VerifyContext *ctx)
2297 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
2298 guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
2299 int i, param_number = 0;
2301 for (i = 0; i < table->rows; ++i) {
2302 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
2304 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
2305 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
2307 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
2308 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
2310 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
2311 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
2313 token = data [MONO_GENERICPARAM_OWNER];
2315 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
2316 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
2318 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
2319 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
2321 if (token != last_token) {
2326 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
2327 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));
2334 verify_method_spec_table (VerifyContext *ctx)
2336 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
2337 guint32 data [MONO_METHODSPEC_SIZE];
2340 for (i = 0; i < table->rows; ++i) {
2341 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
2343 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
2344 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
2346 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
2347 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
2349 if (!is_valid_methodspec_blog (ctx, data [MONO_METHODSPEC_SIGNATURE]))
2350 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
2355 verify_generic_param_constraint_table (VerifyContext *ctx)
2357 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
2358 guint32 data [MONO_GENPARCONSTRAINT_SIZE];
2361 for (i = 0; i < table->rows; ++i) {
2362 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
2364 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
2365 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_TABLE_GENERICPARAM]));
2367 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
2368 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
2370 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
2371 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
2376 verify_tables_data (VerifyContext *ctx)
2378 OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
2379 guint32 size = 0, tables_offset;
2382 for (i = 0; i < 0x2D; ++i) {
2383 MonoTableInfo *table = &ctx->image->tables [i];
2385 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
2386 if (tmp_size < size) {
2394 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
2396 tables_offset = ctx->image->tables_base - ctx->data;
2397 if (!bounds_check_offset (&tables_area, tables_offset, size))
2398 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)));
2400 verify_module_table (ctx);
2402 verify_typeref_table (ctx);
2404 verify_typedef_table (ctx);
2406 verify_field_table (ctx);
2408 verify_method_table (ctx);
2410 verify_param_table (ctx);
2412 verify_interfaceimpl_table (ctx);
2414 verify_memberref_table (ctx);
2416 verify_constant_table (ctx);
2418 verify_cattr_table (ctx);
2420 verify_field_marshal_table (ctx);
2422 verify_decl_security_table (ctx);
2424 verify_class_layout_table (ctx);
2426 verify_field_layout_table (ctx);
2428 verify_standalonesig_table (ctx);
2430 verify_eventmap_table (ctx);
2432 verify_event_table (ctx);
2434 verify_propertymap_table (ctx);
2436 verify_property_table (ctx);
2438 verify_methodimpl_table (ctx);
2440 verify_moduleref_table (ctx);
2442 verify_typespec_table (ctx);
2444 verify_implmap_table (ctx);
2446 verify_fieldrva_table (ctx);
2448 verify_assembly_table (ctx);
2450 verify_assemblyref_table (ctx);
2452 verify_file_table (ctx);
2454 verify_exportedtype_table (ctx);
2456 verify_manifest_resource_table (ctx);
2458 verify_nested_class_table (ctx);
2460 verify_generic_param_table (ctx);
2462 verify_method_spec_table (ctx);
2464 verify_generic_param_constraint_table (ctx);
2468 mono_verifier_is_corlib (MonoImage *image)
2470 gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ?
2471 TRUE : mono_security_core_clr_is_platform_image (image);
2473 return trusted_location && !strcmp ("mscorlib.dll", image->name);
2477 init_verify_context (VerifyContext *ctx, MonoImage *image, GSList **error_list)
2479 memset (ctx, 0, sizeof (VerifyContext));
2481 ctx->report_error = error_list != NULL;
2483 ctx->size = image->raw_data_len;
2484 ctx->data = image->raw_data;
2485 ctx->is_corlib = mono_verifier_is_corlib (image);
2489 cleanup_context (VerifyContext *ctx, GSList **error_list)
2491 g_free (ctx->sections);
2493 *error_list = ctx->errors;
2495 mono_free_verify_list (ctx->errors);
2500 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
2504 if (!mono_verifier_is_enabled_for_image (image))
2507 init_verify_context (&ctx, image, error_list);
2508 ctx.stage = STAGE_PE;
2510 verify_msdos_header (&ctx);
2512 verify_pe_header (&ctx);
2514 verify_pe_optional_header (&ctx);
2516 load_section_table (&ctx);
2518 load_data_directories (&ctx);
2520 verify_import_table (&ctx);
2522 /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
2523 verify_resources_table (&ctx);
2526 return cleanup_context (&ctx, error_list);
2530 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
2534 if (!mono_verifier_is_enabled_for_image (image))
2537 init_verify_context (&ctx, image, error_list);
2538 ctx.stage = STAGE_CLI;
2540 verify_cli_header (&ctx);
2542 verify_metadata_header (&ctx);
2544 verify_tables_schema (&ctx);
2547 return cleanup_context (&ctx, error_list);
2551 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
2555 if (!mono_verifier_is_enabled_for_image (image))
2558 init_verify_context (&ctx, image, error_list);
2559 ctx.stage = STAGE_TABLES;
2561 verify_tables_data (&ctx);
2563 return cleanup_context (&ctx, error_list);
2567 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
2573 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
2579 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
2583 #endif /* DISABLE_VERIFIER */