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)
1132 parse_type (VerifyContext *ctx, const char **_ptr, const char *end)
1138 parse_return_type (VerifyContext *ctx, const char **_ptr, const char *end)
1143 if (!parse_custom_mods (ctx, _ptr, end))
1147 if (!safe_read8 (type, ptr, end))
1148 FAIL (ctx, g_strdup ("ReturnType: Not enough room for the type"));
1150 if (type == MONO_TYPE_VOID || type == MONO_TYPE_TYPEDBYREF) {
1155 //it's a byref, update the cursor ptr
1156 if (type == MONO_TYPE_TYPEDBYREF)
1159 return parse_type (ctx, _ptr, end);
1163 is_valid_field_signature (VerifyContext *ctx, guint32 offset)
1165 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1166 //TODO do proper verification
1167 return blob.size >= 2 && blob.size - 2 >= offset;
1171 is_valid_method_signature (VerifyContext *ctx, guint32 offset)
1173 int size = 0, cconv = 0;
1174 unsigned param_count;
1175 const char *ptr = NULL, *end;
1176 if (!decode_signature_header (ctx, offset, &size, &ptr))
1180 if (!safe_read8 (cconv, ptr, end))
1181 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the call conv"));
1184 FAIL (ctx, g_strdup ("MethodSig: CallConv has 0x80 set"));
1186 if ((cconv & 0x0F) != 0 && (cconv & 0x0F)!= 5)
1187 FAIL (ctx, g_strdup ("MethodSig: CallConv is not Default or Vararg"));
1189 if (!safe_read_cint (param_count, ptr, end))
1190 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the param count"));
1192 if (!parse_return_type (ctx, &ptr, end))
1199 is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
1201 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1202 //TODO do proper verification
1203 return blob.size >= 2 && blob.size - 2 >= offset;
1207 is_vald_cattr_blob (VerifyContext *ctx, guint32 offset)
1209 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1210 //TODO do proper verification
1211 return blob.size >= 1 && blob.size - 1 >= offset;
1215 is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
1217 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1218 //TODO do proper verification
1219 return blob.size >= 1 && blob.size - 1 >= offset;
1223 is_valid_permission_set (VerifyContext *ctx, guint32 offset)
1225 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1226 //TODO do proper verification
1227 return blob.size >= 1 && blob.size - 1 >= offset;
1231 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
1233 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1234 //TODO do proper verification
1235 return blob.size >= 1 && blob.size - 1 >= offset;
1239 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
1241 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1242 //TODO do proper verification
1243 return offset > 0 && blob.size >= 1 && blob.size - 1 >= offset;
1247 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
1249 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1250 //TODO do proper verification
1251 return offset > 0 && blob.size >= 1 && blob.size - 1 >= offset;
1255 is_valid_methodspec_blog (VerifyContext *ctx, guint32 offset)
1257 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1258 //TODO do proper verification
1259 return offset > 0 && blob.size >= 1 && blob.size - 1 >= offset;
1263 is_valid_blob_object (VerifyContext *ctx, guint32 offset)
1265 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1266 guint32 entry_size, bytes;
1268 if (blob.size < offset) {
1273 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1276 if (offset + entry_size + bytes < offset)
1279 return blob.size >= offset + entry_size + bytes;
1283 is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
1285 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1286 guint32 size, entry_size, bytes;
1288 if (blob.size < offset) {
1294 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1297 if (type == MONO_TYPE_STRING) {
1298 //String is encoded as: compressed_int:len len *chars
1301 if (offset > offset + entry_size * 2) //overflow
1303 offset += offset + entry_size * 2;
1304 return offset <= blob.size;
1308 case MONO_TYPE_BOOLEAN:
1313 case MONO_TYPE_CHAR:
1321 case MONO_TYPE_CLASS:
1331 g_assert_not_reached ();
1334 if (size != entry_size)
1338 if(offset > offset + size) //overflow
1341 if (offset + size > blob.size)
1344 if (type == MONO_TYPE_CLASS && read32 (ctx->data + offset))
1350 is_valid_method_header (VerifyContext *ctx, guint32 rva)
1352 //TODO do proper method header validation
1353 return mono_cli_rva_image_map (ctx->image, rva) != INVALID_ADDRESS;
1357 verify_module_table (VerifyContext *ctx)
1359 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
1360 guint32 data [MONO_MODULE_SIZE];
1362 if (table->rows != 1)
1363 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
1365 mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
1367 if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
1368 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
1370 if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
1371 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
1373 if (data [MONO_MODULE_ENC] != 0)
1374 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
1376 if (data [MONO_MODULE_ENCBASE] != 0)
1377 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
1381 verify_typeref_table (VerifyContext *ctx)
1383 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
1384 guint32 data [MONO_TYPEREF_SIZE];
1387 for (i = 0; i < table->rows; ++i) {
1388 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
1389 if (!is_valid_coded_index (ctx, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1390 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d coded index 0x%08x", i, data [MONO_TYPEREF_SCOPE]));
1392 if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1393 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", i));
1395 if (!data [MONO_TYPEREF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAME]))
1396 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d name token 0x%08x", i, data [MONO_TYPEREF_NAME]));
1398 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
1399 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d namespace token 0x%08x", i, data [MONO_TYPEREF_NAMESPACE]));
1403 /*bits 9,11,14,15,19,21,24-31 */
1404 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 14) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
1406 verify_typedef_table (VerifyContext *ctx)
1408 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
1409 guint32 data [MONO_TYPEDEF_SIZE];
1410 guint32 fieldlist = 1, methodlist = 1;
1413 if (table->rows == 0)
1414 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
1416 for (i = 0; i < table->rows; ++i) {
1417 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
1418 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
1419 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
1421 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
1422 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
1424 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
1425 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
1427 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
1428 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
1430 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
1431 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
1433 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
1434 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
1437 if (data [MONO_TYPEDEF_EXTENDS] != 0)
1438 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
1440 if (typedef_is_system_object (ctx, data) && data [MONO_TYPEDEF_EXTENDS] != 0)
1441 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
1443 if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
1444 if (data [MONO_TYPEDEF_EXTENDS])
1445 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
1446 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
1447 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
1449 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
1450 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
1452 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
1453 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
1457 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
1458 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
1460 if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
1461 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
1463 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
1464 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));
1466 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
1467 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
1469 if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
1470 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
1472 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
1473 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));
1476 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
1477 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
1482 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
1484 verify_field_table (VerifyContext *ctx)
1486 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
1487 guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
1490 module_field_list = (guint32)-1;
1491 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
1492 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
1493 module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
1496 for (i = 0; i < table->rows; ++i) {
1497 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
1498 flags = data [MONO_FIELD_FLAGS];
1500 if (flags & INVALID_FIELD_FLAG_BITS)
1501 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
1503 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)
1504 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
1506 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
1507 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
1509 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
1510 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
1512 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
1513 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
1515 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
1516 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
1517 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
1519 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
1520 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
1521 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
1523 if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
1524 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
1525 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
1527 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
1528 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
1529 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
1531 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
1532 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
1534 //TODO verify contant flag
1535 if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
1536 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
1538 if (i + 1 < module_field_list) {
1539 guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
1540 if (!(flags & FIELD_ATTRIBUTE_STATIC))
1541 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
1542 if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
1543 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
1548 /*bits 6,8,9,10,11,13,14,15*/
1549 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 6) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
1551 verify_method_table (VerifyContext *ctx)
1553 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
1554 guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
1555 guint32 paramlist = 1;
1556 gboolean is_ctor, is_cctor;
1560 module_method_list = (guint32)-1;
1561 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
1562 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
1563 module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
1566 for (i = 0; i < table->rows; ++i) {
1567 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
1568 rva = data [MONO_METHOD_RVA];
1569 implflags = data [MONO_METHOD_IMPLFLAGS];
1570 flags = data [MONO_METHOD_FLAGS];
1571 access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
1572 code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
1575 if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
1576 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
1579 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
1581 if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
1582 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
1584 name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
1585 is_ctor = !strcmp (".ctor", name);
1586 is_cctor = !strcmp (".cctor", name);
1588 if ((is_ctor || is_cctor) &&
1589 search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
1590 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
1592 if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
1593 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
1595 if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
1596 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
1597 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
1598 if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
1599 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
1602 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
1603 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
1605 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
1606 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
1608 //XXX no checks against cas stuff 10,11,12,13)
1610 //TODO check iface with .ctor (15,16)
1612 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
1613 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token %08x", i, data [MONO_METHOD_SIGNATURE]));
1615 if (i + 1 < module_method_list) {
1616 if (!(flags & METHOD_ATTRIBUTE_STATIC))
1617 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
1618 if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
1619 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
1620 if (!(access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED || access == METHOD_ATTRIBUTE_PUBLIC || access == METHOD_ATTRIBUTE_PRIVATE))
1621 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public or Private", i));
1624 //TODO check valuetype for synchronized
1626 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
1627 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
1629 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && (flags & METHOD_ATTRIBUTE_VIRTUAL))
1630 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
1632 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
1633 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
1634 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
1636 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
1637 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
1639 //TODO check signature contents
1642 if (flags & METHOD_ATTRIBUTE_ABSTRACT)
1643 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", i));
1644 if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
1645 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
1646 if (!is_valid_method_header (ctx, rva))
1647 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
1649 if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
1650 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
1653 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
1655 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
1656 if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
1657 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
1659 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
1660 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
1662 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
1663 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
1665 if (data [MONO_METHOD_PARAMLIST] == 0)
1666 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
1668 if (data [MONO_METHOD_PARAMLIST] < paramlist)
1669 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));
1671 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
1672 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
1674 paramlist = data [MONO_METHOD_PARAMLIST];
1680 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
1682 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
1683 guint32 row = *current_method;
1684 guint32 paramlist, tmp;
1687 paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
1688 while (row < table->rows) {
1689 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
1690 if (tmp > paramlist) {
1691 *current_method = row;
1692 return tmp - paramlist;
1697 /*no more methods, all params apply to the last one*/
1698 *current_method = table->rows;
1703 #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))
1705 verify_param_table (VerifyContext *ctx)
1707 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
1708 guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
1709 gboolean first_param = TRUE;
1712 remaining_params = get_next_param_count (ctx, ¤t_method);
1714 for (i = 0; i < table->rows; ++i) {
1715 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
1716 flags = data [MONO_PARAM_FLAGS];
1718 if (flags & INVALID_PARAM_FLAGS_BITS)
1719 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
1721 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
1722 if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
1723 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
1725 if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
1726 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
1729 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)
1730 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
1732 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
1733 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
1735 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
1736 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
1738 first_param = FALSE;
1739 sequence = data [MONO_PARAM_SEQUENCE];
1740 if (--remaining_params == 0) {
1741 remaining_params = get_next_param_count (ctx, ¤t_method);
1748 verify_interfaceimpl_table (VerifyContext *ctx)
1750 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
1751 guint32 data [MONO_INTERFACEIMPL_SIZE];
1754 for (i = 0; i < table->rows; ++i) {
1755 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
1756 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
1757 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
1759 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
1760 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
1762 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
1763 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
1768 verify_memberref_table (VerifyContext *ctx)
1770 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
1771 guint32 data [MONO_MEMBERREF_SIZE];
1774 for (i = 0; i < table->rows; ++i) {
1775 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
1777 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
1778 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
1780 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
1781 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
1783 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
1784 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
1786 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
1787 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field 0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
1792 verify_constant_table (VerifyContext *ctx)
1794 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
1795 guint32 data [MONO_CONSTANT_SIZE], type;
1798 for (i = 0; i < table->rows; ++i) {
1799 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
1800 type = data [MONO_CONSTANT_TYPE];
1802 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
1803 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
1805 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
1806 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
1808 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
1809 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
1811 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
1812 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
1817 verify_cattr_table (VerifyContext *ctx)
1819 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1820 guint32 data [MONO_CUSTOM_ATTR_SIZE];
1823 for (i = 0; i < table->rows; ++i) {
1824 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
1826 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
1827 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
1829 if (!is_valid_coded_index (ctx, CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]))
1830 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
1832 if (!is_vald_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
1833 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
1839 verify_field_marshal_table (VerifyContext *ctx)
1841 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
1842 guint32 data [MONO_FIELD_MARSHAL_SIZE];
1845 for (i = 0; i < table->rows; ++i) {
1846 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
1848 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
1849 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
1851 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
1852 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
1854 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
1855 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
1857 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
1858 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
1864 verify_decl_security_table (VerifyContext *ctx)
1866 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
1867 guint32 data [MONO_DECL_SECURITY_SIZE];
1870 for (i = 0; i < table->rows; ++i) {
1871 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
1873 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
1874 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
1876 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
1877 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
1879 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
1880 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
1882 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
1883 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
1889 verify_class_layout_table (VerifyContext *ctx)
1891 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
1892 guint32 data [MONO_CLASS_LAYOUT_SIZE];
1895 for (i = 0; i < table->rows; ++i) {
1896 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
1898 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
1899 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
1901 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
1913 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
1919 verify_field_layout_table (VerifyContext *ctx)
1921 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
1922 guint32 data [MONO_FIELD_LAYOUT_SIZE];
1925 for (i = 0; i < table->rows; ++i) {
1926 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
1928 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
1929 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
1934 verify_standalonesig_table (VerifyContext *ctx)
1936 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
1937 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
1940 for (i = 0; i < table->rows; ++i) {
1941 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
1943 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
1944 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
1949 verify_eventmap_table (VerifyContext *ctx)
1951 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
1952 guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
1955 for (i = 0; i < table->rows; ++i) {
1956 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
1958 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
1959 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
1961 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
1962 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
1964 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
1968 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
1970 verify_event_table (VerifyContext *ctx)
1972 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
1973 MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
1974 guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
1975 gboolean found_add, found_remove;
1978 for (i = 0; i < table->rows; ++i) {
1979 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
1981 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
1982 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
1984 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
1985 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
1987 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
1988 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
1990 //check for Add and Remove
1991 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
1992 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
1994 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
1996 //first we move to the first row for this event
1998 if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
2002 //now move forward looking for AddOn and RemoveOn rows
2003 found_add = found_remove = FALSE;
2004 while (idx < sema_table->rows) {
2005 mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
2006 if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
2008 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
2010 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
2011 found_remove = TRUE;
2012 if (found_add && found_remove)
2018 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2020 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2025 verify_propertymap_table (VerifyContext *ctx)
2027 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
2028 guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
2031 for (i = 0; i < table->rows; ++i) {
2032 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
2034 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2035 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
2037 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
2038 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
2040 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
2044 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
2046 verify_property_table (VerifyContext *ctx)
2048 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
2049 guint32 data [MONO_PROPERTY_SIZE];
2052 for (i = 0; i < table->rows; ++i) {
2053 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
2055 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
2056 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
2058 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
2059 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
2061 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
2062 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
2064 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
2065 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
2066 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
2072 verify_methodimpl_table (VerifyContext *ctx)
2074 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
2075 guint32 data [MONO_METHODIMPL_SIZE];
2078 for (i = 0; i < table->rows; ++i) {
2079 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
2081 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2082 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2084 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2085 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2087 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2088 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2090 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2091 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2093 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2094 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2099 verify_moduleref_table (VerifyContext *ctx)
2101 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
2102 guint32 data [MONO_MODULEREF_SIZE];
2105 for (i = 0; i < table->rows; ++i) {
2106 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
2108 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
2109 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2114 verify_typespec_table (VerifyContext *ctx)
2116 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
2117 guint32 data [MONO_TYPESPEC_SIZE];
2120 for (i = 0; i < table->rows; ++i) {
2121 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
2123 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
2124 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
2128 #define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10))
2130 verify_implmap_table (VerifyContext *ctx)
2132 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
2133 guint32 data [MONO_IMPLMAP_SIZE], cconv;
2136 for (i = 0; i < table->rows; ++i) {
2137 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
2139 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
2140 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
2142 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
2143 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
2144 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
2146 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2147 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
2149 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
2150 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
2152 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2153 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
2155 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
2156 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
2158 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULE].rows + 1)
2159 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
2164 verify_fieldrva_table (VerifyContext *ctx)
2166 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
2167 guint32 data [MONO_FIELD_RVA_SIZE];
2170 for (i = 0; i < table->rows; ++i) {
2171 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
2173 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
2174 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
2176 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2177 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
2181 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 8) | (1 << 14) | (1 << 15))
2183 verify_assembly_table (VerifyContext *ctx)
2185 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
2186 guint32 data [MONO_ASSEMBLY_SIZE], hash;
2189 if (table->rows > 1)
2190 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
2192 for (i = 0; i < table->rows; ++i) {
2193 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
2195 hash = data [MONO_ASSEMBLY_HASH_ALG];
2196 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
2197 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
2199 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
2200 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2202 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY]))
2203 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2205 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
2206 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
2208 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
2209 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
2213 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~(1)
2215 verify_assemblyref_table (VerifyContext *ctx)
2217 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
2218 guint32 data [MONO_ASSEMBLYREF_SIZE];
2221 for (i = 0; i < table->rows; ++i) {
2222 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
2224 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
2225 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
2227 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY]))
2228 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
2230 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
2231 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
2233 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
2234 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
2236 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE]))
2237 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
2241 #define INVALID_FILE_FLAGS_BITS ~(1)
2243 verify_file_table (VerifyContext *ctx)
2245 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
2246 guint32 data [MONO_FILE_SIZE];
2249 for (i = 0; i < table->rows; ++i) {
2250 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
2252 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
2253 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
2255 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
2256 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
2258 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE]))
2259 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
2263 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
2265 verify_exportedtype_table (VerifyContext *ctx)
2267 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
2268 guint32 data [MONO_EXP_TYPE_SIZE];
2271 for (i = 0; i < table->rows; ++i) {
2272 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
2274 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
2275 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
2277 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
2278 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
2280 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
2281 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
2283 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
2284 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
2286 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
2287 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
2289 /*nested type can't have a namespace*/
2290 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
2291 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
2295 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
2297 verify_manifest_resource_table (VerifyContext *ctx)
2299 MonoCLIImageInfo *iinfo = ctx->image->image_info;
2300 MonoCLIHeader *ch = &iinfo->cli_cli_header;
2301 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
2302 guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
2305 resources_size = ch->ch_resources.size;
2307 for (i = 0; i < table->rows; ++i) {
2308 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
2310 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
2311 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
2313 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
2314 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
2316 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
2317 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
2319 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
2320 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
2322 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
2323 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
2325 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
2326 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])));
2328 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
2329 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
2331 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
2332 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
2337 verify_nested_class_table (VerifyContext *ctx)
2339 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
2340 guint32 data [MONO_NESTED_CLASS_SIZE];
2343 for (i = 0; i < table->rows; ++i) {
2344 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
2346 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2347 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
2348 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2349 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
2350 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
2351 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
2355 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
2357 verify_generic_param_table (VerifyContext *ctx)
2359 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
2360 guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
2361 int i, param_number = 0;
2363 for (i = 0; i < table->rows; ++i) {
2364 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
2366 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
2367 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
2369 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
2370 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
2372 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
2373 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
2375 token = data [MONO_GENERICPARAM_OWNER];
2377 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
2378 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
2380 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
2381 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
2383 if (token != last_token) {
2388 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
2389 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));
2396 verify_method_spec_table (VerifyContext *ctx)
2398 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
2399 guint32 data [MONO_METHODSPEC_SIZE];
2402 for (i = 0; i < table->rows; ++i) {
2403 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
2405 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
2406 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
2408 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
2409 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
2411 if (!is_valid_methodspec_blog (ctx, data [MONO_METHODSPEC_SIGNATURE]))
2412 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
2417 verify_generic_param_constraint_table (VerifyContext *ctx)
2419 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
2420 guint32 data [MONO_GENPARCONSTRAINT_SIZE];
2423 for (i = 0; i < table->rows; ++i) {
2424 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
2426 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
2427 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_TABLE_GENERICPARAM]));
2429 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
2430 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
2432 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
2433 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
2438 verify_tables_data (VerifyContext *ctx)
2440 OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
2441 guint32 size = 0, tables_offset;
2444 for (i = 0; i < 0x2D; ++i) {
2445 MonoTableInfo *table = &ctx->image->tables [i];
2447 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
2448 if (tmp_size < size) {
2456 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
2458 tables_offset = ctx->image->tables_base - ctx->data;
2459 if (!bounds_check_offset (&tables_area, tables_offset, size))
2460 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)));
2462 verify_module_table (ctx);
2464 verify_typeref_table (ctx);
2466 verify_typedef_table (ctx);
2468 verify_field_table (ctx);
2470 verify_method_table (ctx);
2472 verify_param_table (ctx);
2474 verify_interfaceimpl_table (ctx);
2476 verify_memberref_table (ctx);
2478 verify_constant_table (ctx);
2480 verify_cattr_table (ctx);
2482 verify_field_marshal_table (ctx);
2484 verify_decl_security_table (ctx);
2486 verify_class_layout_table (ctx);
2488 verify_field_layout_table (ctx);
2490 verify_standalonesig_table (ctx);
2492 verify_eventmap_table (ctx);
2494 verify_event_table (ctx);
2496 verify_propertymap_table (ctx);
2498 verify_property_table (ctx);
2500 verify_methodimpl_table (ctx);
2502 verify_moduleref_table (ctx);
2504 verify_typespec_table (ctx);
2506 verify_implmap_table (ctx);
2508 verify_fieldrva_table (ctx);
2510 verify_assembly_table (ctx);
2512 verify_assemblyref_table (ctx);
2514 verify_file_table (ctx);
2516 verify_exportedtype_table (ctx);
2518 verify_manifest_resource_table (ctx);
2520 verify_nested_class_table (ctx);
2522 verify_generic_param_table (ctx);
2524 verify_method_spec_table (ctx);
2526 verify_generic_param_constraint_table (ctx);
2530 mono_verifier_is_corlib (MonoImage *image)
2532 gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ?
2533 TRUE : mono_security_core_clr_is_platform_image (image);
2535 return trusted_location && !strcmp ("mscorlib.dll", image->name);
2539 init_verify_context (VerifyContext *ctx, MonoImage *image, GSList **error_list)
2541 memset (ctx, 0, sizeof (VerifyContext));
2543 ctx->report_error = error_list != NULL;
2545 ctx->size = image->raw_data_len;
2546 ctx->data = image->raw_data;
2547 ctx->is_corlib = mono_verifier_is_corlib (image);
2551 cleanup_context (VerifyContext *ctx, GSList **error_list)
2553 g_free (ctx->sections);
2555 *error_list = ctx->errors;
2557 mono_free_verify_list (ctx->errors);
2562 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
2566 if (!mono_verifier_is_enabled_for_image (image))
2569 init_verify_context (&ctx, image, error_list);
2570 ctx.stage = STAGE_PE;
2572 verify_msdos_header (&ctx);
2574 verify_pe_header (&ctx);
2576 verify_pe_optional_header (&ctx);
2578 load_section_table (&ctx);
2580 load_data_directories (&ctx);
2582 verify_import_table (&ctx);
2584 /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
2585 verify_resources_table (&ctx);
2588 return cleanup_context (&ctx, error_list);
2592 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
2596 if (!mono_verifier_is_enabled_for_image (image))
2599 init_verify_context (&ctx, image, error_list);
2600 ctx.stage = STAGE_CLI;
2602 verify_cli_header (&ctx);
2604 verify_metadata_header (&ctx);
2606 verify_tables_schema (&ctx);
2609 return cleanup_context (&ctx, error_list);
2613 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
2617 if (!mono_verifier_is_enabled_for_image (image))
2620 init_verify_context (&ctx, image, error_list);
2621 ctx.stage = STAGE_TABLES;
2623 verify_tables_data (&ctx);
2625 return cleanup_context (&ctx, error_list);
2629 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
2635 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
2641 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
2645 #endif /* DISABLE_VERIFIER */