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 FAIL(__ctx, __msg) \
254 if ((__ctx)->report_error) \
255 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
256 (__ctx)->valid = 0; \
260 #define CHECK_STATE() do { if (!ctx.valid) goto cleanup; } while (0)
262 #define CHECK_ERROR() do { if (!ctx->valid) return; } while (0)
265 pe_signature_offset (VerifyContext *ctx)
267 return read32 (ctx->data + 0x3c);
271 pe_header_offset (VerifyContext *ctx)
273 return read32 (ctx->data + 0x3c) + 4;
277 bounds_check_virtual_address (VerifyContext *ctx, guint32 rva, guint32 size)
281 if (rva + size < rva) //overflow
284 if (ctx->stage > STAGE_PE) {
285 MonoCLIImageInfo *iinfo = ctx->image->image_info;
286 const int top = iinfo->cli_section_count;
287 MonoSectionTable *tables = iinfo->cli_section_tables;
290 for (i = 0; i < top; i++) {
291 guint32 base = tables->st_virtual_address;
292 guint32 end = base + tables->st_raw_data_size;
294 if (rva >= base && rva + size <= end)
297 /*if ((addr >= tables->st_virtual_address) &&
298 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
300 return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
310 for (i = 0; i < ctx->section_count; ++i) {
311 guint32 base = ctx->sections [i].baseRVA;
312 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
313 if (rva >= base && rva + size <= end)
320 bounds_check_datadir (DataDirectory *dir, guint32 offset, guint32 size)
322 if (dir->translated_offset > offset)
324 if (dir->size < size)
326 return offset + size <= dir->translated_offset + dir->size;
330 bounds_check_offset (OffsetAndSize *off, guint32 offset, guint32 size)
332 if (off->offset > offset)
335 if (off->size < size)
338 return offset + size <= off->offset + off->size;
342 translate_rva (VerifyContext *ctx, guint32 rva)
346 if (ctx->stage > STAGE_PE)
347 return mono_cli_rva_image_map (ctx->image, rva);
352 for (i = 0; i < ctx->section_count; ++i) {
353 guint32 base = ctx->sections [i].baseRVA;
354 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
355 if (rva >= base && rva <= end) {
356 guint32 res = (rva - base) + ctx->sections [i].baseOffset;
358 return res >= ctx->size ? INVALID_OFFSET : res;
362 return INVALID_OFFSET;
366 verify_msdos_header (VerifyContext *ctx)
370 ADD_ERROR (ctx, g_strdup ("Not enough space for the MS-DOS header"));
371 if (ctx->data [0] != 0x4d || ctx->data [1] != 0x5a)
372 ADD_ERROR (ctx, g_strdup ("Invalid MS-DOS watermark"));
373 lfanew = pe_signature_offset (ctx);
374 if (lfanew > ctx->size - 4)
375 ADD_ERROR (ctx, g_strdup ("MS-DOS lfanew offset points to outside of the file"));
379 verify_pe_header (VerifyContext *ctx)
381 guint32 offset = pe_signature_offset (ctx);
382 const char *pe_header = ctx->data + offset;
383 if (pe_header [0] != 'P' || pe_header [1] != 'E' ||pe_header [2] != 0 ||pe_header [3] != 0)
384 ADD_ERROR (ctx, g_strdup ("Invalid PE header watermark"));
388 if (offset > ctx->size - 20)
389 ADD_ERROR (ctx, g_strdup ("File with truncated pe header"));
390 if (read16 (pe_header) != 0x14c)
391 ADD_ERROR (ctx, g_strdup ("Invalid PE header Machine value"));
395 verify_pe_optional_header (VerifyContext *ctx)
397 guint32 offset = pe_header_offset (ctx);
398 guint32 header_size, file_alignment;
399 const char *pe_header = ctx->data + offset;
400 const char *pe_optional_header = pe_header + 20;
402 header_size = read16 (pe_header + 16);
405 if (header_size < 2) /*must be at least 2 or we won't be able to read magic*/
406 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
408 if (offset > ctx->size - header_size || header_size > ctx->size)
409 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
411 if (read16 (pe_optional_header) == 0x10b) {
412 if (header_size != 224)
413 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header size %d", header_size));
415 /* LAMESPEC MS plays around this value and ignore it during validation
416 if (read32 (pe_optional_header + 28) != 0x400000)
417 ADD_ERROR (ctx, g_strdup_printf ("Invalid Image base %x", read32 (pe_optional_header + 28)));*/
418 if (read32 (pe_optional_header + 32) != 0x2000)
419 ADD_ERROR (ctx, g_strdup_printf ("Invalid Section Aligmnent %x", read32 (pe_optional_header + 32)));
420 file_alignment = read32 (pe_optional_header + 36);
421 if (file_alignment != 0x200 && file_alignment != 0x1000)
422 ADD_ERROR (ctx, g_strdup_printf ("Invalid file Aligmnent %x", file_alignment));
423 /* All the junk in the middle is irrelevant, specially for mono. */
424 if (read32 (pe_optional_header + 92) > 0x10)
425 ADD_ERROR (ctx, g_strdup_printf ("Too many data directories %x", read32 (pe_optional_header + 92)));
427 if (read16 (pe_optional_header) == 0x20B)
428 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle PE32+"));
430 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header magic %d", read16 (pe_optional_header)));
435 load_section_table (VerifyContext *ctx)
438 SectionHeader *sections;
439 guint32 offset = pe_header_offset (ctx);
440 const char *ptr = ctx->data + offset;
441 guint16 num_sections = ctx->section_count = read16 (ptr + 2);
443 offset += 244;/*FIXME, this constant is different under PE32+*/
446 if (num_sections * 40 > ctx->size - offset)
447 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
449 sections = ctx->sections = g_new0 (SectionHeader, num_sections);
450 for (i = 0; i < num_sections; ++i) {
451 sections [i].size = read32 (ptr + 8);
452 sections [i].baseRVA = read32 (ptr + 12);
453 sections [i].baseOffset = read32 (ptr + 20);
454 sections [i].rellocationsRVA = read32 (ptr + 24);
455 sections [i].numberOfRelocations = read16 (ptr + 32);
459 ptr = ctx->data + offset; /*reset it to the beggining*/
460 for (i = 0; i < num_sections; ++i) {
461 guint32 raw_size, flags;
462 if (sections [i].baseOffset == 0)
463 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with intialized data only"));
464 if (sections [i].baseOffset >= ctx->size)
465 ADD_ERROR (ctx, g_strdup_printf ("Invalid PointerToRawData %x points beyond EOF", sections [i].baseOffset));
466 if (sections [i].size > ctx->size - sections [i].baseOffset)
467 ADD_ERROR (ctx, g_strdup ("Invalid VirtualSize points beyond EOF"));
469 raw_size = read32 (ptr + 16);
470 if (raw_size < sections [i].size)
471 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with SizeOfRawData < VirtualSize"));
473 if (raw_size > ctx->size - sections [i].baseOffset)
474 ADD_ERROR (ctx, g_strdup_printf ("Invalid SizeOfRawData %x points beyond EOF", raw_size));
476 if (sections [i].rellocationsRVA || sections [i].numberOfRelocations)
477 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't handle section relocation"));
479 flags = read32 (ptr + 36);
480 /*TODO 0xFE0000E0 is all flags from cil-coff.h OR'd. Make it a less magical number*/
481 if (flags == 0 || (flags & ~0xFE0000E0) != 0)
482 ADD_ERROR (ctx, g_strdup_printf ("Invalid section flags %x", flags));
489 is_valid_data_directory (int i)
491 /*LAMESPEC 4 == certificate 6 == debug, MS uses both*/
492 return i == 1 || i == 2 || i == 5 || i == 12 || i == 14 || i == 4 || i == 6;
496 load_data_directories (VerifyContext *ctx)
498 guint32 offset = pe_header_offset (ctx) + 116; /*FIXME, this constant is different under PE32+*/
499 const char *ptr = ctx->data + offset;
502 for (i = 0; i < 16; ++i) {
503 guint32 rva = read32 (ptr);
504 guint32 size = read32 (ptr + 4);
506 /*LAMESPEC the authenticode data directory format is different. We don't support CAS, so lets ignore for now.*/
507 if (i == CERTIFICATE_TABLE_IDX) {
511 if ((rva != 0 || size != 0) && !is_valid_data_directory (i))
512 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d", i));
514 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
515 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d rva/size pair %x/%x", i, rva, size));
517 ctx->data_directories [i].rva = rva;
518 ctx->data_directories [i].size = size;
519 ctx->data_directories [i].translated_offset = translate_rva (ctx, rva);
525 #define SIZE_OF_MSCOREE (sizeof ("mscoree.dll"))
527 #define SIZE_OF_CORMAIN (sizeof ("_CorExeMain"))
530 verify_hint_name_table (VerifyContext *ctx, guint32 import_rva, const char *table_name)
533 guint32 hint_table_rva;
535 import_rva = translate_rva (ctx, import_rva);
536 g_assert (import_rva != INVALID_OFFSET);
538 hint_table_rva = read32 (ctx->data + import_rva);
539 if (!bounds_check_virtual_address (ctx, hint_table_rva, SIZE_OF_CORMAIN + 2))
540 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint/Name rva %d for %s", hint_table_rva, table_name));
542 hint_table_rva = translate_rva (ctx, hint_table_rva);
543 g_assert (hint_table_rva != INVALID_OFFSET);
544 ptr = ctx->data + hint_table_rva + 2;
546 if (memcmp ("_CorExeMain", ptr, SIZE_OF_CORMAIN) && memcmp ("_CorDllMain", ptr, SIZE_OF_CORMAIN)) {
547 char name[SIZE_OF_CORMAIN];
548 memcpy (name, ptr, SIZE_OF_CORMAIN);
549 name [SIZE_OF_CORMAIN - 1] = 0;
550 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint / Name: '%s'", name));
555 verify_import_table (VerifyContext *ctx)
557 DataDirectory it = ctx->data_directories [IMPORT_TABLE_IDX];
558 guint32 offset = it.translated_offset;
559 const char *ptr = ctx->data + offset;
560 guint32 name_rva, ilt_rva, iat_rva;
562 g_assert (offset != INVALID_OFFSET);
565 ADD_ERROR (ctx, g_strdup_printf ("Import table size %d is smaller than 40", it.size));
567 ilt_rva = read32 (ptr);
568 if (!bounds_check_virtual_address (ctx, ilt_rva, 8))
569 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Lookup Table rva %x", ilt_rva));
571 name_rva = read32 (ptr + 12);
572 if (!bounds_check_virtual_address (ctx, name_rva, SIZE_OF_MSCOREE))
573 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name rva %x", name_rva));
575 iat_rva = read32 (ptr + 16);
576 if (!bounds_check_virtual_address (ctx, iat_rva, 8))
577 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Address Table rva %x", iat_rva));
579 if (iat_rva != ctx->data_directories [IAT_IDX].rva)
580 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));
582 name_rva = translate_rva (ctx, name_rva);
583 g_assert (name_rva != INVALID_OFFSET);
584 ptr = ctx->data + name_rva;
586 if (memcmp ("mscoree.dll", ptr, SIZE_OF_MSCOREE)) {
587 char name[SIZE_OF_MSCOREE];
588 memcpy (name, ptr, SIZE_OF_MSCOREE);
589 name [SIZE_OF_MSCOREE - 1] = 0;
590 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name: '%s'", name));
593 verify_hint_name_table (ctx, ilt_rva, "Import Lookup Table");
595 verify_hint_name_table (ctx, iat_rva, "Import Address Table");
599 verify_resources_table (VerifyContext *ctx)
601 DataDirectory it = ctx->data_directories [RESOURCE_TABLE_IDX];
603 guint16 named_entries, id_entries;
604 const char *ptr, *root, *end;
610 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));
612 offset = it.translated_offset;
613 root = ptr = ctx->data + offset;
614 end = root + it.size;
616 g_assert (offset != INVALID_OFFSET);
618 named_entries = read16 (ptr + 12);
619 id_entries = read16 (ptr + 14);
621 if ((named_entries + id_entries) * 8 + 16 > it.size)
622 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));
624 /* XXX at least one unmanaged resource is added due to a call to AssemblyBuilder::DefineVersionInfoResource ()
625 if (named_entries || id_entries)
626 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support full verification of PECOFF resources"));
630 /*----------nothing from here on can use data_directory---*/
633 get_data_dir (VerifyContext *ctx, int idx)
635 MonoCLIImageInfo *iinfo = ctx->image->image_info;
636 MonoPEDirEntry *entry= &iinfo->cli_header.datadir.pe_export_table;
640 res.rva = entry->rva;
641 res.size = entry->size;
642 res.translated_offset = translate_rva (ctx, res.rva);
647 verify_cli_header (VerifyContext *ctx)
649 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
655 ADD_ERROR (ctx, g_strdup_printf ("CLI header missing"));
658 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size in data directory %d must be 72", it.size));
660 offset = it.translated_offset;
661 ptr = ctx->data + offset;
663 g_assert (offset != INVALID_OFFSET);
665 if (read16 (ptr) != 72)
666 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size %d must be 72", read16 (ptr)));
668 if (!bounds_check_virtual_address (ctx, read32 (ptr + 8), read32 (ptr + 12)))
669 ADD_ERROR (ctx, g_strdup_printf ("Invalid medatata section rva/size pair %x/%x", read32 (ptr + 8), read32 (ptr + 12)));
672 if (!read32 (ptr + 8) || !read32 (ptr + 12))
673 ADD_ERROR (ctx, g_strdup_printf ("Missing medatata section in the CLI header"));
675 if ((read32 (ptr + 16) & ~0x0001000B) != 0)
676 ADD_ERROR (ctx, g_strdup_printf ("Invalid CLI header flags"));
679 for (i = 0; i < 6; ++i) {
680 guint32 rva = read32 (ptr);
681 guint32 size = read32 (ptr + 4);
683 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
684 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli section %i rva/size pair %x/%x", i, rva, size));
689 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't support cli header section %d", i));
694 pad4 (guint32 offset)
696 if (offset & 0x3) //pad to the next 4 byte boundary
697 offset = (offset & ~0x3) + 4;
702 verify_metadata_header (VerifyContext *ctx)
705 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
709 offset = it.translated_offset;
710 ptr = ctx->data + offset;
711 g_assert (offset != INVALID_OFFSET);
713 //build a directory entry for the metadata root
715 it.rva = read32 (ptr);
717 it.size = read32 (ptr);
718 it.translated_offset = offset = translate_rva (ctx, it.rva);
720 ptr = ctx->data + offset;
721 g_assert (offset != INVALID_OFFSET);
724 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small %d (at least 20 bytes required for initial decoding)", it.size));
726 if (read32 (ptr) != 0x424A5342)
727 ADD_ERROR (ctx, g_strdup_printf ("Invalid metadata signature, expected 0x424A5342 but got %08x", read32 (ptr)));
729 offset = pad4 (offset + 16 + read32 (ptr + 12));
731 if (!bounds_check_datadir (&it, offset, 4))
732 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));
734 ptr = ctx->data + offset; //move to streams header
736 if (read16 (ptr + 2) < 3)
737 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section must have at least 3 streams (#~, #GUID and #Blob"));
742 for (i = 0; i < 5; ++i) {
743 guint32 stream_off, stream_size;
744 int string_size, stream_idx;
746 if (!bounds_check_datadir (&it, offset, 8))
747 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));
749 stream_off = it.translated_offset + read32 (ptr);
750 stream_size = read32 (ptr + 4);
752 if (!bounds_check_datadir (&it, stream_off, stream_size))
753 ADD_ERROR (ctx, g_strdup_printf ("Invalid stream header %d offset/size pair %x/%x", 0, stream_off, stream_size));
758 for (string_size = 0; string_size < 32; ++string_size) {
759 if (!bounds_check_datadir (&it, offset++, 1))
760 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small to decode stream header %d name", i));
761 if (!ptr [string_size])
765 if (ptr [string_size])
766 ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d name larger than 32 bytes", i));
768 if (!strncmp ("#Strings", ptr, 9))
769 stream_idx = STRINGS_STREAM;
770 else if (!strncmp ("#US", ptr, 4))
771 stream_idx = USER_STRINGS_STREAM;
772 else if (!strncmp ("#Blob", ptr, 6))
773 stream_idx = BLOB_STREAM;
774 else if (!strncmp ("#GUID", ptr, 6))
775 stream_idx = GUID_STREAM;
776 else if (!strncmp ("#~", ptr, 3))
777 stream_idx = TILDE_STREAM;
779 ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d invalid name %s", i, ptr));
781 if (ctx->metadata_streams [stream_idx].offset != 0)
782 ADD_ERROR (ctx, g_strdup_printf ("Duplicated metadata stream header %s", ptr));
784 ctx->metadata_streams [stream_idx].offset = stream_off;
785 ctx->metadata_streams [stream_idx].size = stream_size;
787 offset = pad4 (offset);
788 ptr = ctx->data + offset;
791 if (!ctx->metadata_streams [TILDE_STREAM].size)
792 ADD_ERROR (ctx, g_strdup_printf ("Metadata #~ stream missing"));
793 if (!ctx->metadata_streams [GUID_STREAM].size)
794 ADD_ERROR (ctx, g_strdup_printf ("Metadata guid stream missing"));
795 if (!ctx->metadata_streams [BLOB_STREAM].size)
796 ADD_ERROR (ctx, g_strdup_printf ("Metadata blob stream missing"));
801 verify_tables_schema (VerifyContext *ctx)
803 OffsetAndSize tables_area = ctx->metadata_streams [TILDE_STREAM];
804 unsigned offset = tables_area.offset;
805 const char *ptr = ctx->data + offset;
806 guint64 valid_tables;
810 //printf ("tables_area size %d offset %x %s\n", tables_area.size, tables_area.offset, ctx->image->name);
811 if (tables_area.size < 24)
812 ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for initial decoding (requires 24 bytes)", tables_area.size));
814 //printf ("ptr %x %x\n", ptr[4], ptr[5]);
815 if (ptr [4] != 2 && ptr [4] != 1)
816 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata major version %d, expected 2", ptr [4]));
818 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata minor version %d, expected 0", ptr [5]));
820 if ((ptr [6] & ~0x7) != 0)
821 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]));
823 valid_tables = read64 (ptr + 8);
825 for (i = 0; i < 64; ++i) {
826 if (!(valid_tables & ((guint64)1 << i)))
829 /*MS Extensions: 0x3 0x5 0x7 0x13 0x16
830 Unused: 0x1E 0x1F 0x2D-0x3F
831 We don't care about the MS extensions.*/
832 if (i == 0x3 || i == 0x5 || i == 0x7 || i == 0x13 || i == 0x16)
833 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifies doesn't support MS specific table %x", i));
834 if (i == 0x1E || i == 0x1F || i >= 0x2D)
835 ADD_ERROR (ctx, g_strdup_printf ("Invalid table %x", i));
839 if (tables_area.size < 24 + count * 4)
840 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));
843 for (i = 0; i < 64; ++i) {
844 if (valid_tables & ((guint64)1 << i)) {
845 guint32 row_count = read32 (ptr);
846 if (row_count > (1 << 24) - 1)
847 ADD_ERROR (ctx, g_strdup_printf ("Invalid Table %d row count: %d. Mono only supports 16777215 rows", i, row_count));
853 /*----------nothing from here on can use data_directory or metadata_streams ---*/
856 get_col_offset (VerifyContext *ctx, int table, int column)
858 guint32 bitfield = ctx->image->tables [table].size_bitfield;
862 offset += mono_metadata_table_size (bitfield, column);
868 get_col_size (VerifyContext *ctx, int table, int column)
870 return mono_metadata_table_size (ctx->image->tables [table].size_bitfield, column);
874 get_metadata_stream (VerifyContext *ctx, MonoStreamHeader *header)
877 res.offset = header->data - ctx->data;
878 res.size = header->size;
884 is_valid_string_full (VerifyContext *ctx, guint32 offset, gboolean allow_empty)
886 OffsetAndSize strings = get_metadata_stream (ctx, &ctx->image->heap_strings);
888 const char *data = ctx->data + strings.offset;
890 if (offset >= strings.size)
892 if (data + offset < data) //FIXME, use a generalized and smart unsigned add with overflow check and fix the whole thing
895 if (!mono_utf8_validate_and_len_with_bounds (data + offset, strings.size - offset, &length, NULL))
897 return allow_empty || length > 0;
901 is_valid_string (VerifyContext *ctx, guint32 offset)
903 return is_valid_string_full (ctx, offset, TRUE);
907 is_valid_non_empty_string (VerifyContext *ctx, guint32 offset)
909 return is_valid_string_full (ctx, offset, FALSE);
913 is_valid_guid (VerifyContext *ctx, guint32 offset)
915 OffsetAndSize guids = get_metadata_stream (ctx, &ctx->image->heap_guid);
916 return guids.size >= 8 && guids.size - 8 >= offset;
920 get_coded_index_token (int token_kind, guint32 coded_token)
922 guint32 bits = coded_index_desc [token_kind];
923 return coded_token >> bits;
927 get_coded_index_table (int kind, guint32 coded_token)
929 guint32 idx, bits = coded_index_desc [kind];
931 idx = coded_token & ((1 << bits) - 1);
932 return coded_index_desc [kind + idx];
936 make_coded_token (int kind, guint32 table, guint32 table_idx)
938 guint32 bits = coded_index_desc [kind++];
939 guint32 tables = coded_index_desc [kind++];
941 for (i = 0; i < tables; ++i) {
942 if (coded_index_desc [kind++] == table)
943 return ((table_idx + 1) << bits) | i;
945 g_assert_not_reached ();
950 is_valid_coded_index (VerifyContext *ctx, int token_kind, guint32 coded_token)
952 guint32 bits = coded_index_desc [token_kind++];
953 guint32 table_count = coded_index_desc [token_kind++];
954 guint32 table = coded_token & ((1 << bits) - 1);
955 guint32 token = coded_token >> bits;
957 if (table >= table_count)
960 /*token_kind points to the first table idx*/
961 table = coded_index_desc [token_kind + table];
963 if (table == INVALID_TABLE)
965 return token <= ctx->image->tables [table].rows;
972 MonoTableInfo *table;
976 token_locator (const void *a, const void *b)
978 RowLocator *loc = (RowLocator *)a;
979 unsigned const char *row = (unsigned const char *)b;
980 guint32 token = loc->col_size == 2 ? read16 (row + loc->col_offset) : read32 (row + loc->col_offset);
982 VERIFIER_DEBUG ( printf ("\tfound token %x at idx %d\n", token, ((const char*)row - loc->table->base) / loc->table->row_size) );
983 return (int)loc->token - (int)token;
987 search_sorted_table (VerifyContext *ctx, int table, int column, guint32 coded_token)
989 MonoTableInfo *tinfo = &ctx->image->tables [table];
991 const char *res, *base;
992 locator.token = coded_token;
993 locator.col_offset = get_col_offset (ctx, table, column);
994 locator.col_size = get_col_size (ctx, table, column);
995 locator.table = tinfo;
999 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) );
1000 res = bsearch (&locator, base, tinfo->rows, tinfo->row_size, token_locator);
1004 return (res - base) / tinfo->row_size;
1007 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1009 get_string_ptr (VerifyContext *ctx, guint offset)
1011 return ctx->image->heap_strings.data + offset;
1014 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1016 string_cmp (VerifyContext *ctx, const char *str, guint offset)
1019 return strcmp (str, "");
1021 return strcmp (str, get_string_ptr (ctx, offset));
1025 typedef_is_system_object (VerifyContext *ctx, guint32 *data)
1027 return ctx->is_corlib && !string_cmp (ctx, "System", data [MONO_TYPEDEF_NAME]) && !string_cmp (ctx, "Object", data [MONO_TYPEDEF_NAMESPACE]);
1031 decode_value (const char *_ptr, unsigned available, unsigned *value, unsigned *size)
1034 const unsigned char *ptr = (const unsigned char *)_ptr;
1042 if ((b & 0x80) == 0) {
1045 } else if ((b & 0x40) == 0) {
1049 *value = ((b & 0x3f) << 8 | ptr [1]);
1054 *value = ((b & 0x1f) << 24) |
1064 decode_signature_header (VerifyContext *ctx, guint32 offset, int *size, const char **first_byte)
1066 MonoStreamHeader blob = ctx->image->heap_blob;
1067 guint32 value, enc_size;
1069 if (offset >= blob.size)
1072 if (!decode_value (blob.data + offset, blob.size - offset, &value, &enc_size))
1075 if (offset + enc_size + value < offset)
1078 if (offset + enc_size + value > blob.size)
1082 *first_byte = blob.data + offset + enc_size;
1087 safe_read (const char **_ptr, const char *limit, void *dest, int size)
1089 const char *ptr = *_ptr;
1090 if (ptr + size > limit)
1094 *((guint8*)dest) = *((guint8*)ptr);
1098 *((guint16*)dest) = read16 (ptr);
1102 *((guint32*)dest) = read32 (ptr);
1111 safe_read_compressed_int (const char **_ptr, const char *limit, unsigned *dest)
1114 const char *ptr = *_ptr;
1115 gboolean res = decode_value (ptr, limit - ptr, dest, &size);
1120 #define safe_read8(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 1)
1121 #define safe_read_cint(VAR, PTR, LIMIT) safe_read_compressed_int (&PTR, LIMIT, &VAR)
1122 #define safe_read16(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 2)
1123 #define safe_read32(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 4)
1126 parse_custom_mods (VerifyContext *ctx, const char **_ptr, const char *end)
1128 const char *ptr = *_ptr;
1133 if (!safe_read8 (type, ptr, end))
1134 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the type"));
1136 if (type != MONO_TYPE_CMOD_REQD && type != MONO_TYPE_CMOD_OPT) {
1141 if (!safe_read_cint (token, ptr, end))
1142 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the token"));
1144 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1145 FAIL (ctx, g_strdup_printf ("CustomMod: invalid TypeDefOrRef token %x", token));
1153 parse_type (VerifyContext *ctx, const char **_ptr, const char *end)
1155 const char *ptr = *_ptr;
1158 if (!safe_read8 (type, ptr, end))
1159 FAIL (ctx, g_strdup ("Type: Not enough room for the type"));
1161 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_PTR) ||
1162 (type >= MONO_TYPE_VALUETYPE && type <= MONO_TYPE_GENERICINST) ||
1163 (type >= MONO_TYPE_I && type <= MONO_TYPE_U) ||
1164 (type >= MONO_TYPE_FNPTR && type <= MONO_TYPE_MVAR)))
1165 FAIL (ctx, g_strdup_printf ("Type: Invalid type kind %x\n", type));
1172 parse_return_type (VerifyContext *ctx, const char **_ptr, const char *end)
1177 if (!parse_custom_mods (ctx, _ptr, end))
1181 if (!safe_read8 (type, ptr, end))
1182 FAIL (ctx, g_strdup ("ReturnType: Not enough room for the type"));
1184 if (type == MONO_TYPE_VOID || type == MONO_TYPE_TYPEDBYREF) {
1189 //it's a byref, update the cursor ptr
1190 if (type == MONO_TYPE_BYREF)
1193 return parse_type (ctx, _ptr, end);
1197 parse_param (VerifyContext *ctx, const char **_ptr, const char *end)
1202 if (!parse_custom_mods (ctx, _ptr, end))
1206 if (!safe_read8 (type, ptr, end))
1207 FAIL (ctx, g_strdup ("Param: Not enough room for the type"));
1209 if (type == MONO_TYPE_TYPEDBYREF) {
1214 //it's a byref, update the cursor ptr
1215 if (type == MONO_TYPE_BYREF)
1218 return parse_type (ctx, _ptr, end);
1222 is_valid_field_signature (VerifyContext *ctx, guint32 offset)
1224 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1225 //TODO do proper verification
1226 return blob.size >= 2 && blob.size - 2 >= offset;
1230 is_valid_method_signature (VerifyContext *ctx, guint32 offset)
1232 int size = 0, cconv = 0;
1233 unsigned param_count = 0, gparam_count = 0, i;
1234 const char *ptr = NULL, *end;
1236 if (!decode_signature_header (ctx, offset, &size, &ptr))
1237 FAIL (ctx, g_strdup ("MethodSig: Could not decode signature header"));
1240 if (!safe_read8 (cconv, ptr, end))
1241 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the call conv"));
1244 FAIL (ctx, g_strdup ("MethodSig: CallConv has 0x80 set"));
1246 if ((cconv & 0x0F) != 0 && (cconv & 0x0F)!= 5)
1247 FAIL (ctx, g_strdup ("MethodSig: CallConv is not Default or Vararg"));
1249 if ((cconv & 0x10) && !safe_read_cint (gparam_count, ptr, end))
1250 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the generic param count"));
1252 if ((cconv & 0x10) && gparam_count == 0)
1253 FAIL (ctx, g_strdup ("MethodSig: Signature with generics but zero arity"));
1255 if (!safe_read_cint (param_count, ptr, end))
1256 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the param count"));
1258 if (!parse_return_type (ctx, &ptr, end))
1259 FAIL (ctx, g_strdup ("MethodSig: Error parsing return type"));
1261 for (i = 0; i < param_count; ++i) {
1262 if (!parse_param (ctx, &ptr, end))
1263 FAIL (ctx, g_strdup_printf ("MethodSig: Error parsing arg %d", i));
1270 is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
1272 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1273 //TODO do proper verification
1274 return blob.size >= 2 && blob.size - 2 >= offset;
1278 is_vald_cattr_blob (VerifyContext *ctx, guint32 offset)
1280 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1281 //TODO do proper verification
1282 return blob.size >= 1 && blob.size - 1 >= offset;
1286 is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
1288 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1289 //TODO do proper verification
1290 return blob.size >= 1 && blob.size - 1 >= offset;
1294 is_valid_permission_set (VerifyContext *ctx, guint32 offset)
1296 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1297 //TODO do proper verification
1298 return blob.size >= 1 && blob.size - 1 >= offset;
1302 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
1304 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1305 //TODO do proper verification
1306 return blob.size >= 1 && blob.size - 1 >= offset;
1310 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
1312 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1313 //TODO do proper verification
1314 return offset > 0 && blob.size >= 1 && blob.size - 1 >= offset;
1318 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
1320 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1321 //TODO do proper verification
1322 return offset > 0 && blob.size >= 1 && blob.size - 1 >= offset;
1326 is_valid_methodspec_blog (VerifyContext *ctx, guint32 offset)
1328 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1329 //TODO do proper verification
1330 return offset > 0 && blob.size >= 1 && blob.size - 1 >= offset;
1334 is_valid_blob_object (VerifyContext *ctx, guint32 offset)
1336 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1337 guint32 entry_size, bytes;
1339 if (blob.size < offset) {
1344 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1347 if (offset + entry_size + bytes < offset)
1350 return blob.size >= offset + entry_size + bytes;
1354 is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
1356 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1357 guint32 size, entry_size, bytes;
1359 if (blob.size < offset) {
1365 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1368 if (type == MONO_TYPE_STRING) {
1369 //String is encoded as: compressed_int:len len *chars
1372 if (offset > offset + entry_size * 2) //overflow
1374 offset += offset + entry_size * 2;
1375 return offset <= blob.size;
1379 case MONO_TYPE_BOOLEAN:
1384 case MONO_TYPE_CHAR:
1392 case MONO_TYPE_CLASS:
1402 g_assert_not_reached ();
1405 if (size != entry_size)
1409 if(offset > offset + size) //overflow
1412 if (offset + size > blob.size)
1415 if (type == MONO_TYPE_CLASS && read32 (ctx->data + offset))
1421 is_valid_method_header (VerifyContext *ctx, guint32 rva)
1423 //TODO do proper method header validation
1424 return mono_cli_rva_image_map (ctx->image, rva) != INVALID_ADDRESS;
1428 verify_module_table (VerifyContext *ctx)
1430 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
1431 guint32 data [MONO_MODULE_SIZE];
1433 if (table->rows != 1)
1434 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
1436 mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
1438 if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
1439 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
1441 if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
1442 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
1444 if (data [MONO_MODULE_ENC] != 0)
1445 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
1447 if (data [MONO_MODULE_ENCBASE] != 0)
1448 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
1452 verify_typeref_table (VerifyContext *ctx)
1454 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
1455 guint32 data [MONO_TYPEREF_SIZE];
1458 for (i = 0; i < table->rows; ++i) {
1459 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
1460 if (!is_valid_coded_index (ctx, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1461 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d coded index 0x%08x", i, data [MONO_TYPEREF_SCOPE]));
1463 if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1464 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", i));
1466 if (!data [MONO_TYPEREF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAME]))
1467 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d name token 0x%08x", i, data [MONO_TYPEREF_NAME]));
1469 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
1470 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d namespace token 0x%08x", i, data [MONO_TYPEREF_NAMESPACE]));
1474 /*bits 9,11,14,15,19,21,24-31 */
1475 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 14) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
1477 verify_typedef_table (VerifyContext *ctx)
1479 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
1480 guint32 data [MONO_TYPEDEF_SIZE];
1481 guint32 fieldlist = 1, methodlist = 1;
1484 if (table->rows == 0)
1485 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
1487 for (i = 0; i < table->rows; ++i) {
1488 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
1489 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
1490 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
1492 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
1493 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
1495 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
1496 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
1498 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
1499 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
1501 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
1502 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
1504 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
1505 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
1508 if (data [MONO_TYPEDEF_EXTENDS] != 0)
1509 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
1511 if (typedef_is_system_object (ctx, data) && data [MONO_TYPEDEF_EXTENDS] != 0)
1512 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
1514 if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
1515 if (data [MONO_TYPEDEF_EXTENDS])
1516 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
1517 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
1518 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
1520 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
1521 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
1523 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
1524 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
1528 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
1529 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
1531 if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
1532 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
1534 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
1535 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));
1537 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
1538 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
1540 if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
1541 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
1543 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
1544 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));
1547 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
1548 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
1553 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
1555 verify_field_table (VerifyContext *ctx)
1557 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
1558 guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
1561 module_field_list = (guint32)-1;
1562 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
1563 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
1564 module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
1567 for (i = 0; i < table->rows; ++i) {
1568 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
1569 flags = data [MONO_FIELD_FLAGS];
1571 if (flags & INVALID_FIELD_FLAG_BITS)
1572 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
1574 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)
1575 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
1577 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
1578 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
1580 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
1581 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
1583 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
1584 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
1586 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
1587 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
1588 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
1590 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
1591 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
1592 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
1594 if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
1595 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
1596 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
1598 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
1599 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
1600 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
1602 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
1603 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
1605 //TODO verify contant flag
1606 if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
1607 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
1609 if (i + 1 < module_field_list) {
1610 guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
1611 if (!(flags & FIELD_ATTRIBUTE_STATIC))
1612 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
1613 if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
1614 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
1619 /*bits 6,8,9,10,11,13,14,15*/
1620 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 6) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
1622 verify_method_table (VerifyContext *ctx)
1624 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
1625 guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
1626 guint32 paramlist = 1;
1627 gboolean is_ctor, is_cctor;
1631 module_method_list = (guint32)-1;
1632 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
1633 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
1634 module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
1637 for (i = 0; i < table->rows; ++i) {
1638 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
1639 rva = data [MONO_METHOD_RVA];
1640 implflags = data [MONO_METHOD_IMPLFLAGS];
1641 flags = data [MONO_METHOD_FLAGS];
1642 access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
1643 code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
1646 if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
1647 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
1650 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
1652 if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
1653 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
1655 name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
1656 is_ctor = !strcmp (".ctor", name);
1657 is_cctor = !strcmp (".cctor", name);
1659 if ((is_ctor || is_cctor) &&
1660 search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
1661 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
1663 if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
1664 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
1666 if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
1667 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
1668 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
1669 if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
1670 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
1673 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
1674 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
1676 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
1677 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
1679 //XXX no checks against cas stuff 10,11,12,13)
1681 //TODO check iface with .ctor (15,16)
1683 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
1684 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
1686 if (i + 1 < module_method_list) {
1687 if (!(flags & METHOD_ATTRIBUTE_STATIC))
1688 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
1689 if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
1690 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
1691 if (!(access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED || access == METHOD_ATTRIBUTE_PUBLIC || access == METHOD_ATTRIBUTE_PRIVATE))
1692 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public or Private", i));
1695 //TODO check valuetype for synchronized
1697 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
1698 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
1700 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && (flags & METHOD_ATTRIBUTE_VIRTUAL))
1701 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
1703 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
1704 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
1705 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
1707 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
1708 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
1710 //TODO check signature contents
1713 if (flags & METHOD_ATTRIBUTE_ABSTRACT)
1714 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", i));
1715 if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
1716 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
1717 if (!is_valid_method_header (ctx, rva))
1718 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
1720 if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
1721 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
1724 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
1726 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
1727 if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
1728 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
1730 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
1731 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
1733 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
1734 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
1736 if (data [MONO_METHOD_PARAMLIST] == 0)
1737 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
1739 if (data [MONO_METHOD_PARAMLIST] < paramlist)
1740 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));
1742 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
1743 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
1745 paramlist = data [MONO_METHOD_PARAMLIST];
1751 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
1753 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
1754 guint32 row = *current_method;
1755 guint32 paramlist, tmp;
1758 paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
1759 while (row < table->rows) {
1760 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
1761 if (tmp > paramlist) {
1762 *current_method = row;
1763 return tmp - paramlist;
1768 /*no more methods, all params apply to the last one*/
1769 *current_method = table->rows;
1774 #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))
1776 verify_param_table (VerifyContext *ctx)
1778 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
1779 guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
1780 gboolean first_param = TRUE;
1783 remaining_params = get_next_param_count (ctx, ¤t_method);
1785 for (i = 0; i < table->rows; ++i) {
1786 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
1787 flags = data [MONO_PARAM_FLAGS];
1789 if (flags & INVALID_PARAM_FLAGS_BITS)
1790 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
1792 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
1793 if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
1794 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
1796 if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
1797 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
1800 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)
1801 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
1803 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
1804 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
1806 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
1807 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
1809 first_param = FALSE;
1810 sequence = data [MONO_PARAM_SEQUENCE];
1811 if (--remaining_params == 0) {
1812 remaining_params = get_next_param_count (ctx, ¤t_method);
1819 verify_interfaceimpl_table (VerifyContext *ctx)
1821 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
1822 guint32 data [MONO_INTERFACEIMPL_SIZE];
1825 for (i = 0; i < table->rows; ++i) {
1826 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
1827 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
1828 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
1830 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
1831 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
1833 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
1834 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
1839 verify_memberref_table (VerifyContext *ctx)
1841 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
1842 guint32 data [MONO_MEMBERREF_SIZE];
1845 for (i = 0; i < table->rows; ++i) {
1846 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
1848 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
1849 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
1851 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
1852 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
1854 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
1855 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
1857 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
1858 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field 0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
1863 verify_constant_table (VerifyContext *ctx)
1865 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
1866 guint32 data [MONO_CONSTANT_SIZE], type;
1869 for (i = 0; i < table->rows; ++i) {
1870 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
1871 type = data [MONO_CONSTANT_TYPE];
1873 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
1874 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
1876 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
1877 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
1879 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
1880 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
1882 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
1883 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
1888 verify_cattr_table (VerifyContext *ctx)
1890 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1891 guint32 data [MONO_CUSTOM_ATTR_SIZE];
1894 for (i = 0; i < table->rows; ++i) {
1895 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
1897 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
1898 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
1900 if (!is_valid_coded_index (ctx, CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]))
1901 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
1903 if (!is_vald_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
1904 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
1910 verify_field_marshal_table (VerifyContext *ctx)
1912 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
1913 guint32 data [MONO_FIELD_MARSHAL_SIZE];
1916 for (i = 0; i < table->rows; ++i) {
1917 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
1919 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
1920 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
1922 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
1923 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
1925 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
1926 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
1928 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
1929 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
1935 verify_decl_security_table (VerifyContext *ctx)
1937 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
1938 guint32 data [MONO_DECL_SECURITY_SIZE];
1941 for (i = 0; i < table->rows; ++i) {
1942 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
1944 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
1945 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
1947 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
1948 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
1950 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
1951 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
1953 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
1954 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
1960 verify_class_layout_table (VerifyContext *ctx)
1962 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
1963 guint32 data [MONO_CLASS_LAYOUT_SIZE];
1966 for (i = 0; i < table->rows; ++i) {
1967 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
1969 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
1970 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
1972 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
1984 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
1990 verify_field_layout_table (VerifyContext *ctx)
1992 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
1993 guint32 data [MONO_FIELD_LAYOUT_SIZE];
1996 for (i = 0; i < table->rows; ++i) {
1997 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
1999 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2000 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
2005 verify_standalonesig_table (VerifyContext *ctx)
2007 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
2008 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
2011 for (i = 0; i < table->rows; ++i) {
2012 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
2014 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
2015 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
2020 verify_eventmap_table (VerifyContext *ctx)
2022 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
2023 guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
2026 for (i = 0; i < table->rows; ++i) {
2027 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
2029 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2030 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
2032 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
2033 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
2035 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
2039 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
2041 verify_event_table (VerifyContext *ctx)
2043 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
2044 MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
2045 guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
2046 gboolean found_add, found_remove;
2049 for (i = 0; i < table->rows; ++i) {
2050 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
2052 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
2053 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
2055 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
2056 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
2058 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
2059 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
2061 //check for Add and Remove
2062 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
2063 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
2065 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
2067 //first we move to the first row for this event
2069 if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
2073 //now move forward looking for AddOn and RemoveOn rows
2074 found_add = found_remove = FALSE;
2075 while (idx < sema_table->rows) {
2076 mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
2077 if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
2079 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
2081 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
2082 found_remove = TRUE;
2083 if (found_add && found_remove)
2089 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2091 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2096 verify_propertymap_table (VerifyContext *ctx)
2098 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
2099 guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
2102 for (i = 0; i < table->rows; ++i) {
2103 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
2105 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2106 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
2108 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
2109 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
2111 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
2115 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
2117 verify_property_table (VerifyContext *ctx)
2119 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
2120 guint32 data [MONO_PROPERTY_SIZE];
2123 for (i = 0; i < table->rows; ++i) {
2124 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
2126 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
2127 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
2129 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
2130 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
2132 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
2133 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
2135 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
2136 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
2137 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
2143 verify_methodimpl_table (VerifyContext *ctx)
2145 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
2146 guint32 data [MONO_METHODIMPL_SIZE];
2149 for (i = 0; i < table->rows; ++i) {
2150 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
2152 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2153 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2155 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2156 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2158 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2159 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2161 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2162 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2164 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2165 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2170 verify_moduleref_table (VerifyContext *ctx)
2172 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
2173 guint32 data [MONO_MODULEREF_SIZE];
2176 for (i = 0; i < table->rows; ++i) {
2177 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
2179 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
2180 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2185 verify_typespec_table (VerifyContext *ctx)
2187 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
2188 guint32 data [MONO_TYPESPEC_SIZE];
2191 for (i = 0; i < table->rows; ++i) {
2192 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
2194 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
2195 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
2199 #define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10))
2201 verify_implmap_table (VerifyContext *ctx)
2203 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
2204 guint32 data [MONO_IMPLMAP_SIZE], cconv;
2207 for (i = 0; i < table->rows; ++i) {
2208 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
2210 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
2211 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
2213 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
2214 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
2215 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
2217 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2218 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
2220 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
2221 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
2223 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2224 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
2226 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
2227 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
2229 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULE].rows + 1)
2230 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
2235 verify_fieldrva_table (VerifyContext *ctx)
2237 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
2238 guint32 data [MONO_FIELD_RVA_SIZE];
2241 for (i = 0; i < table->rows; ++i) {
2242 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
2244 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
2245 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
2247 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2248 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
2252 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 8) | (1 << 14) | (1 << 15))
2254 verify_assembly_table (VerifyContext *ctx)
2256 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
2257 guint32 data [MONO_ASSEMBLY_SIZE], hash;
2260 if (table->rows > 1)
2261 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
2263 for (i = 0; i < table->rows; ++i) {
2264 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
2266 hash = data [MONO_ASSEMBLY_HASH_ALG];
2267 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
2268 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
2270 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
2271 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2273 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY]))
2274 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2276 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
2277 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
2279 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
2280 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
2284 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~(1)
2286 verify_assemblyref_table (VerifyContext *ctx)
2288 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
2289 guint32 data [MONO_ASSEMBLYREF_SIZE];
2292 for (i = 0; i < table->rows; ++i) {
2293 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
2295 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
2296 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
2298 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY]))
2299 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
2301 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
2302 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
2304 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
2305 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
2307 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE]))
2308 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
2312 #define INVALID_FILE_FLAGS_BITS ~(1)
2314 verify_file_table (VerifyContext *ctx)
2316 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
2317 guint32 data [MONO_FILE_SIZE];
2320 for (i = 0; i < table->rows; ++i) {
2321 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
2323 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
2324 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
2326 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
2327 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
2329 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE]))
2330 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
2334 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
2336 verify_exportedtype_table (VerifyContext *ctx)
2338 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
2339 guint32 data [MONO_EXP_TYPE_SIZE];
2342 for (i = 0; i < table->rows; ++i) {
2343 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
2345 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
2346 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
2348 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
2349 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
2351 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
2352 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
2354 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
2355 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
2357 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
2358 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
2360 /*nested type can't have a namespace*/
2361 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
2362 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
2366 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
2368 verify_manifest_resource_table (VerifyContext *ctx)
2370 MonoCLIImageInfo *iinfo = ctx->image->image_info;
2371 MonoCLIHeader *ch = &iinfo->cli_cli_header;
2372 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
2373 guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
2376 resources_size = ch->ch_resources.size;
2378 for (i = 0; i < table->rows; ++i) {
2379 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
2381 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
2382 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
2384 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
2385 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
2387 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
2388 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
2390 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
2391 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
2393 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
2394 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
2396 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
2397 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])));
2399 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
2400 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
2402 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
2403 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
2408 verify_nested_class_table (VerifyContext *ctx)
2410 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
2411 guint32 data [MONO_NESTED_CLASS_SIZE];
2414 for (i = 0; i < table->rows; ++i) {
2415 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
2417 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2418 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
2419 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2420 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
2421 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
2422 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
2426 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
2428 verify_generic_param_table (VerifyContext *ctx)
2430 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
2431 guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
2432 int i, param_number = 0;
2434 for (i = 0; i < table->rows; ++i) {
2435 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
2437 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
2438 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
2440 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
2441 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
2443 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
2444 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
2446 token = data [MONO_GENERICPARAM_OWNER];
2448 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
2449 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
2451 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
2452 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
2454 if (token != last_token) {
2459 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
2460 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));
2467 verify_method_spec_table (VerifyContext *ctx)
2469 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
2470 guint32 data [MONO_METHODSPEC_SIZE];
2473 for (i = 0; i < table->rows; ++i) {
2474 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
2476 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
2477 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
2479 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
2480 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
2482 if (!is_valid_methodspec_blog (ctx, data [MONO_METHODSPEC_SIGNATURE]))
2483 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
2488 verify_generic_param_constraint_table (VerifyContext *ctx)
2490 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
2491 guint32 data [MONO_GENPARCONSTRAINT_SIZE];
2494 for (i = 0; i < table->rows; ++i) {
2495 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
2497 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
2498 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_TABLE_GENERICPARAM]));
2500 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
2501 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
2503 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
2504 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
2509 verify_tables_data (VerifyContext *ctx)
2511 OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
2512 guint32 size = 0, tables_offset;
2515 for (i = 0; i < 0x2D; ++i) {
2516 MonoTableInfo *table = &ctx->image->tables [i];
2518 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
2519 if (tmp_size < size) {
2527 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
2529 tables_offset = ctx->image->tables_base - ctx->data;
2530 if (!bounds_check_offset (&tables_area, tables_offset, size))
2531 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)));
2533 verify_module_table (ctx);
2535 verify_typeref_table (ctx);
2537 verify_typedef_table (ctx);
2539 verify_field_table (ctx);
2541 verify_method_table (ctx);
2543 verify_param_table (ctx);
2545 verify_interfaceimpl_table (ctx);
2547 verify_memberref_table (ctx);
2549 verify_constant_table (ctx);
2551 verify_cattr_table (ctx);
2553 verify_field_marshal_table (ctx);
2555 verify_decl_security_table (ctx);
2557 verify_class_layout_table (ctx);
2559 verify_field_layout_table (ctx);
2561 verify_standalonesig_table (ctx);
2563 verify_eventmap_table (ctx);
2565 verify_event_table (ctx);
2567 verify_propertymap_table (ctx);
2569 verify_property_table (ctx);
2571 verify_methodimpl_table (ctx);
2573 verify_moduleref_table (ctx);
2575 verify_typespec_table (ctx);
2577 verify_implmap_table (ctx);
2579 verify_fieldrva_table (ctx);
2581 verify_assembly_table (ctx);
2583 verify_assemblyref_table (ctx);
2585 verify_file_table (ctx);
2587 verify_exportedtype_table (ctx);
2589 verify_manifest_resource_table (ctx);
2591 verify_nested_class_table (ctx);
2593 verify_generic_param_table (ctx);
2595 verify_method_spec_table (ctx);
2597 verify_generic_param_constraint_table (ctx);
2601 mono_verifier_is_corlib (MonoImage *image)
2603 gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ?
2604 TRUE : mono_security_core_clr_is_platform_image (image);
2606 return trusted_location && !strcmp ("mscorlib.dll", image->name);
2610 init_verify_context (VerifyContext *ctx, MonoImage *image, GSList **error_list)
2612 memset (ctx, 0, sizeof (VerifyContext));
2614 ctx->report_error = error_list != NULL;
2616 ctx->size = image->raw_data_len;
2617 ctx->data = image->raw_data;
2618 ctx->is_corlib = mono_verifier_is_corlib (image);
2622 cleanup_context (VerifyContext *ctx, GSList **error_list)
2624 g_free (ctx->sections);
2626 *error_list = ctx->errors;
2628 mono_free_verify_list (ctx->errors);
2633 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
2637 if (!mono_verifier_is_enabled_for_image (image))
2640 init_verify_context (&ctx, image, error_list);
2641 ctx.stage = STAGE_PE;
2643 verify_msdos_header (&ctx);
2645 verify_pe_header (&ctx);
2647 verify_pe_optional_header (&ctx);
2649 load_section_table (&ctx);
2651 load_data_directories (&ctx);
2653 verify_import_table (&ctx);
2655 /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
2656 verify_resources_table (&ctx);
2659 return cleanup_context (&ctx, error_list);
2663 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
2667 if (!mono_verifier_is_enabled_for_image (image))
2670 init_verify_context (&ctx, image, error_list);
2671 ctx.stage = STAGE_CLI;
2673 verify_cli_header (&ctx);
2675 verify_metadata_header (&ctx);
2677 verify_tables_schema (&ctx);
2680 return cleanup_context (&ctx, error_list);
2684 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
2688 if (!mono_verifier_is_enabled_for_image (image))
2691 init_verify_context (&ctx, image, error_list);
2692 ctx.stage = STAGE_TABLES;
2694 verify_tables_data (&ctx);
2696 return cleanup_context (&ctx, error_list);
2700 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
2706 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
2712 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
2716 #endif /* DISABLE_VERIFIER */