2 * metadata-verify.c: Metadata verfication support
5 * Mono Project (http://www.mono-project.com)
7 * Copyright (C) 2005-2008 Novell, Inc. (http://www.novell.com)
9 #include <mono/metadata/object-internals.h>
10 #include <mono/metadata/verify.h>
11 #include <mono/metadata/verify-internals.h>
12 #include <mono/metadata/opcodes.h>
13 #include <mono/metadata/tabledefs.h>
14 #include <mono/metadata/reflection.h>
15 #include <mono/metadata/debug-helpers.h>
16 #include <mono/metadata/mono-endian.h>
17 #include <mono/metadata/metadata.h>
18 #include <mono/metadata/metadata-internals.h>
19 #include <mono/metadata/class-internals.h>
20 #include <mono/metadata/tokentype.h>
21 #include <mono/metadata/security-manager.h>
22 #include <mono/metadata/security-core-clr.h>
23 #include <mono/metadata/cil-coff.h>
24 #include <mono/metadata/attrdefs.h>
25 #include <mono/utils/strenc.h>
30 #ifndef DISABLE_VERIFIER
32 TODO add fail fast mode
33 TODO add PE32+ support
34 TODO verify the entry point RVA and content.
35 TODO load_section_table and load_data_directories must take PE32+ into account
36 TODO add section relocation support
37 TODO verify the relocation table, since we really don't use, no need so far.
38 TODO do full PECOFF resources verification
39 TODO verify in the CLI header entry point and resources
40 TODO implement null token typeref validation
41 TODO verify table wide invariants for typedef (sorting and uniqueness)
42 TODO implement proper authenticode data directory validation
43 TODO verify properties that require multiple tables to be valid
44 FIXME use subtraction based bounds checking to avoid overflows
45 FIXME get rid of metadata_streams and other fields from VerifyContext
48 #ifdef MONO_VERIFIER_DEBUG
49 #define VERIFIER_DEBUG(code) do { code; } while (0)
51 #define VERIFIER_DEBUG(code)
54 #define INVALID_OFFSET ((guint32)-1)
55 #define INVALID_ADDRESS 0xffffffff
65 RESOURCE_TABLE_IDX = 2,
66 CERTIFICATE_TABLE_IDX = 4,
67 RELOCATION_TABLE_IDX = 5,
81 #define INVALID_TABLE (0xFF)
82 /*format: number of bits, number of tables, tables{n. tables} */
83 const static unsigned char coded_index_desc[] = {
84 #define TYPEDEF_OR_REF_DESC (0)
91 #define HAS_CONSTANT_DESC (TYPEDEF_OR_REF_DESC + 5)
98 #define HAS_CATTR_DESC (HAS_CONSTANT_DESC + 5)
106 MONO_TABLE_INTERFACEIMPL,
107 MONO_TABLE_MEMBERREF,
109 MONO_TABLE_DECLSECURITY,
112 MONO_TABLE_STANDALONESIG,
113 MONO_TABLE_MODULEREF,
116 MONO_TABLE_ASSEMBLYREF,
118 MONO_TABLE_EXPORTEDTYPE,
119 MONO_TABLE_MANIFESTRESOURCE,
121 #define HAS_FIELD_MARSHAL_DESC (HAS_CATTR_DESC + 21)
127 #define HAS_DECL_SECURITY_DESC (HAS_FIELD_MARSHAL_DESC + 4)
134 #define MEMBERREF_PARENT_DESC (HAS_DECL_SECURITY_DESC + 5)
143 #define HAS_SEMANTICS_DESC (MEMBERREF_PARENT_DESC + 7)
149 #define METHODDEF_OR_REF_DESC (HAS_SEMANTICS_DESC + 4)
153 MONO_TABLE_MEMBERREF,
155 #define MEMBER_FORWARDED_DESC (METHODDEF_OR_REF_DESC + 4)
161 #define IMPLEMENTATION_DESC (MEMBER_FORWARDED_DESC + 4)
165 MONO_TABLE_ASSEMBLYREF,
166 MONO_TABLE_EXPORTEDTYPE,
168 #define CATTR_TYPE_DESC (IMPLEMENTATION_DESC + 5)
174 MONO_TABLE_MEMBERREF,
177 #define RES_SCOPE_DESC (CATTR_TYPE_DESC + 7)
181 MONO_TABLE_MODULEREF,
182 MONO_TABLE_ASSEMBLYREF,
185 #define TYPE_OR_METHODDEF_DESC (RES_SCOPE_DESC + 6)
195 guint32 translated_offset;
207 guint32 rellocationsRVA;
208 guint16 numberOfRelocations;
223 gboolean report_error;
226 DataDirectory data_directories [16];
227 guint32 section_count;
228 SectionHeader *sections;
230 OffsetAndSize metadata_streams [5]; //offset from begin of the image
233 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception) \
235 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
236 vinfo->info.status = __status; \
237 vinfo->info.message = ( __msg); \
238 vinfo->exception_type = (__exception); \
239 (__ctx)->errors = g_slist_prepend ((__ctx)->errors, vinfo); \
243 #define ADD_ERROR(__ctx, __msg) \
245 if ((__ctx)->report_error) \
246 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
247 (__ctx)->valid = 0; \
251 #define FAIL(__ctx, __msg) \
253 if ((__ctx)->report_error) \
254 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
255 (__ctx)->valid = 0; \
259 #define CHECK_STATE() do { if (!ctx.valid) goto cleanup; } while (0)
261 #define CHECK_ERROR() do { if (!ctx->valid) return; } while (0)
263 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
264 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
266 #if SIZEOF_VOID_P == 4
267 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
269 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
272 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
275 dword_align (const char *ptr)
277 #if SIZEOF_VOID_P == 8
278 return (const char *) (((guint64) (ptr + 3)) & ~3);
280 return (const char *) (((guint32) (ptr + 3)) & ~3);
285 pe_signature_offset (VerifyContext *ctx)
287 return read32 (ctx->data + 0x3c);
291 pe_header_offset (VerifyContext *ctx)
293 return read32 (ctx->data + 0x3c) + 4;
297 bounds_check_virtual_address (VerifyContext *ctx, guint32 rva, guint32 size)
301 if (rva + size < rva) //overflow
304 if (ctx->stage > STAGE_PE) {
305 MonoCLIImageInfo *iinfo = ctx->image->image_info;
306 const int top = iinfo->cli_section_count;
307 MonoSectionTable *tables = iinfo->cli_section_tables;
310 for (i = 0; i < top; i++) {
311 guint32 base = tables->st_virtual_address;
312 guint32 end = base + tables->st_raw_data_size;
314 if (rva >= base && rva + size <= end)
317 /*if ((addr >= tables->st_virtual_address) &&
318 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
320 return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
330 for (i = 0; i < ctx->section_count; ++i) {
331 guint32 base = ctx->sections [i].baseRVA;
332 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
333 if (rva >= base && rva + size <= end)
340 bounds_check_datadir (DataDirectory *dir, guint32 offset, guint32 size)
342 if (dir->translated_offset > offset)
344 if (dir->size < size)
346 return offset + size <= dir->translated_offset + dir->size;
350 bounds_check_offset (OffsetAndSize *off, guint32 offset, guint32 size)
352 if (off->offset > offset)
355 if (off->size < size)
358 return offset + size <= off->offset + off->size;
362 translate_rva (VerifyContext *ctx, guint32 rva)
366 if (ctx->stage > STAGE_PE)
367 return mono_cli_rva_image_map (ctx->image, rva);
372 for (i = 0; i < ctx->section_count; ++i) {
373 guint32 base = ctx->sections [i].baseRVA;
374 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
375 if (rva >= base && rva <= end) {
376 guint32 res = (rva - base) + ctx->sections [i].baseOffset;
378 return res >= ctx->size ? INVALID_OFFSET : res;
382 return INVALID_OFFSET;
386 verify_msdos_header (VerifyContext *ctx)
390 ADD_ERROR (ctx, g_strdup ("Not enough space for the MS-DOS header"));
391 if (ctx->data [0] != 0x4d || ctx->data [1] != 0x5a)
392 ADD_ERROR (ctx, g_strdup ("Invalid MS-DOS watermark"));
393 lfanew = pe_signature_offset (ctx);
394 if (lfanew > ctx->size - 4)
395 ADD_ERROR (ctx, g_strdup ("MS-DOS lfanew offset points to outside of the file"));
399 verify_pe_header (VerifyContext *ctx)
401 guint32 offset = pe_signature_offset (ctx);
402 const char *pe_header = ctx->data + offset;
403 if (pe_header [0] != 'P' || pe_header [1] != 'E' ||pe_header [2] != 0 ||pe_header [3] != 0)
404 ADD_ERROR (ctx, g_strdup ("Invalid PE header watermark"));
408 if (offset > ctx->size - 20)
409 ADD_ERROR (ctx, g_strdup ("File with truncated pe header"));
410 if (read16 (pe_header) != 0x14c)
411 ADD_ERROR (ctx, g_strdup ("Invalid PE header Machine value"));
415 verify_pe_optional_header (VerifyContext *ctx)
417 guint32 offset = pe_header_offset (ctx);
418 guint32 header_size, file_alignment;
419 const char *pe_header = ctx->data + offset;
420 const char *pe_optional_header = pe_header + 20;
422 header_size = read16 (pe_header + 16);
425 if (header_size < 2) /*must be at least 2 or we won't be able to read magic*/
426 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
428 if (offset > ctx->size - header_size || header_size > ctx->size)
429 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
431 if (read16 (pe_optional_header) == 0x10b) {
432 if (header_size != 224)
433 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header size %d", header_size));
435 /* LAMESPEC MS plays around this value and ignore it during validation
436 if (read32 (pe_optional_header + 28) != 0x400000)
437 ADD_ERROR (ctx, g_strdup_printf ("Invalid Image base %x", read32 (pe_optional_header + 28)));*/
438 if (read32 (pe_optional_header + 32) != 0x2000)
439 ADD_ERROR (ctx, g_strdup_printf ("Invalid Section Aligmnent %x", read32 (pe_optional_header + 32)));
440 file_alignment = read32 (pe_optional_header + 36);
441 if (file_alignment != 0x200 && file_alignment != 0x1000)
442 ADD_ERROR (ctx, g_strdup_printf ("Invalid file Aligmnent %x", file_alignment));
443 /* All the junk in the middle is irrelevant, specially for mono. */
444 if (read32 (pe_optional_header + 92) > 0x10)
445 ADD_ERROR (ctx, g_strdup_printf ("Too many data directories %x", read32 (pe_optional_header + 92)));
447 if (read16 (pe_optional_header) == 0x20B)
448 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle PE32+"));
450 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header magic %d", read16 (pe_optional_header)));
455 load_section_table (VerifyContext *ctx)
458 SectionHeader *sections;
459 guint32 offset = pe_header_offset (ctx);
460 const char *ptr = ctx->data + offset;
461 guint16 num_sections = ctx->section_count = read16 (ptr + 2);
463 offset += 244;/*FIXME, this constant is different under PE32+*/
466 if (num_sections * 40 > ctx->size - offset)
467 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
469 sections = ctx->sections = g_new0 (SectionHeader, num_sections);
470 for (i = 0; i < num_sections; ++i) {
471 sections [i].size = read32 (ptr + 8);
472 sections [i].baseRVA = read32 (ptr + 12);
473 sections [i].baseOffset = read32 (ptr + 20);
474 sections [i].rellocationsRVA = read32 (ptr + 24);
475 sections [i].numberOfRelocations = read16 (ptr + 32);
479 ptr = ctx->data + offset; /*reset it to the beggining*/
480 for (i = 0; i < num_sections; ++i) {
481 guint32 raw_size, flags;
482 if (sections [i].baseOffset == 0)
483 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with intialized data only"));
484 if (sections [i].baseOffset >= ctx->size)
485 ADD_ERROR (ctx, g_strdup_printf ("Invalid PointerToRawData %x points beyond EOF", sections [i].baseOffset));
486 if (sections [i].size > ctx->size - sections [i].baseOffset)
487 ADD_ERROR (ctx, g_strdup ("Invalid VirtualSize points beyond EOF"));
489 raw_size = read32 (ptr + 16);
490 if (raw_size < sections [i].size)
491 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with SizeOfRawData < VirtualSize"));
493 if (raw_size > ctx->size - sections [i].baseOffset)
494 ADD_ERROR (ctx, g_strdup_printf ("Invalid SizeOfRawData %x points beyond EOF", raw_size));
496 if (sections [i].rellocationsRVA || sections [i].numberOfRelocations)
497 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't handle section relocation"));
499 flags = read32 (ptr + 36);
500 /*TODO 0xFE0000E0 is all flags from cil-coff.h OR'd. Make it a less magical number*/
501 if (flags == 0 || (flags & ~0xFE0000E0) != 0)
502 ADD_ERROR (ctx, g_strdup_printf ("Invalid section flags %x", flags));
509 is_valid_data_directory (int i)
511 /*LAMESPEC 4 == certificate 6 == debug, MS uses both*/
512 return i == 1 || i == 2 || i == 5 || i == 12 || i == 14 || i == 4 || i == 6;
516 load_data_directories (VerifyContext *ctx)
518 guint32 offset = pe_header_offset (ctx) + 116; /*FIXME, this constant is different under PE32+*/
519 const char *ptr = ctx->data + offset;
522 for (i = 0; i < 16; ++i) {
523 guint32 rva = read32 (ptr);
524 guint32 size = read32 (ptr + 4);
526 /*LAMESPEC the authenticode data directory format is different. We don't support CAS, so lets ignore for now.*/
527 if (i == CERTIFICATE_TABLE_IDX) {
531 if ((rva != 0 || size != 0) && !is_valid_data_directory (i))
532 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d", i));
534 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
535 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d rva/size pair %x/%x", i, rva, size));
537 ctx->data_directories [i].rva = rva;
538 ctx->data_directories [i].size = size;
539 ctx->data_directories [i].translated_offset = translate_rva (ctx, rva);
545 #define SIZE_OF_MSCOREE (sizeof ("mscoree.dll"))
547 #define SIZE_OF_CORMAIN (sizeof ("_CorExeMain"))
550 verify_hint_name_table (VerifyContext *ctx, guint32 import_rva, const char *table_name)
553 guint32 hint_table_rva;
555 import_rva = translate_rva (ctx, import_rva);
556 g_assert (import_rva != INVALID_OFFSET);
558 hint_table_rva = read32 (ctx->data + import_rva);
559 if (!bounds_check_virtual_address (ctx, hint_table_rva, SIZE_OF_CORMAIN + 2))
560 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint/Name rva %d for %s", hint_table_rva, table_name));
562 hint_table_rva = translate_rva (ctx, hint_table_rva);
563 g_assert (hint_table_rva != INVALID_OFFSET);
564 ptr = ctx->data + hint_table_rva + 2;
566 if (memcmp ("_CorExeMain", ptr, SIZE_OF_CORMAIN) && memcmp ("_CorDllMain", ptr, SIZE_OF_CORMAIN)) {
567 char name[SIZE_OF_CORMAIN];
568 memcpy (name, ptr, SIZE_OF_CORMAIN);
569 name [SIZE_OF_CORMAIN - 1] = 0;
570 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint / Name: '%s'", name));
575 verify_import_table (VerifyContext *ctx)
577 DataDirectory it = ctx->data_directories [IMPORT_TABLE_IDX];
578 guint32 offset = it.translated_offset;
579 const char *ptr = ctx->data + offset;
580 guint32 name_rva, ilt_rva, iat_rva;
582 g_assert (offset != INVALID_OFFSET);
585 ADD_ERROR (ctx, g_strdup_printf ("Import table size %d is smaller than 40", it.size));
587 ilt_rva = read32 (ptr);
588 if (ilt_rva && !bounds_check_virtual_address (ctx, ilt_rva, 8))
589 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Lookup Table rva %x", ilt_rva));
591 name_rva = read32 (ptr + 12);
592 if (name_rva && !bounds_check_virtual_address (ctx, name_rva, SIZE_OF_MSCOREE))
593 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name rva %x", name_rva));
595 iat_rva = read32 (ptr + 16);
597 if (!bounds_check_virtual_address (ctx, iat_rva, 8))
598 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Address Table rva %x", iat_rva));
600 if (iat_rva != ctx->data_directories [IAT_IDX].rva)
601 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));
605 name_rva = translate_rva (ctx, name_rva);
606 g_assert (name_rva != INVALID_OFFSET);
607 ptr = ctx->data + name_rva;
609 if (memcmp ("mscoree.dll", ptr, SIZE_OF_MSCOREE)) {
610 char name[SIZE_OF_MSCOREE];
611 memcpy (name, ptr, SIZE_OF_MSCOREE);
612 name [SIZE_OF_MSCOREE - 1] = 0;
613 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name: '%s'", name));
618 verify_hint_name_table (ctx, ilt_rva, "Import Lookup Table");
623 verify_hint_name_table (ctx, iat_rva, "Import Address Table");
627 verify_resources_table (VerifyContext *ctx)
629 DataDirectory it = ctx->data_directories [RESOURCE_TABLE_IDX];
631 guint16 named_entries, id_entries;
632 const char *ptr, *root, *end;
638 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));
640 offset = it.translated_offset;
641 root = ptr = ctx->data + offset;
642 end = root + it.size;
644 g_assert (offset != INVALID_OFFSET);
646 named_entries = read16 (ptr + 12);
647 id_entries = read16 (ptr + 14);
649 if ((named_entries + id_entries) * 8 + 16 > it.size)
650 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));
652 /* XXX at least one unmanaged resource is added due to a call to AssemblyBuilder::DefineVersionInfoResource ()
653 if (named_entries || id_entries)
654 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support full verification of PECOFF resources"));
658 /*----------nothing from here on can use data_directory---*/
661 get_data_dir (VerifyContext *ctx, int idx)
663 MonoCLIImageInfo *iinfo = ctx->image->image_info;
664 MonoPEDirEntry *entry= &iinfo->cli_header.datadir.pe_export_table;
668 res.rva = entry->rva;
669 res.size = entry->size;
670 res.translated_offset = translate_rva (ctx, res.rva);
675 verify_cli_header (VerifyContext *ctx)
677 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
683 ADD_ERROR (ctx, g_strdup_printf ("CLI header missing"));
686 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size in data directory %d must be 72", it.size));
688 offset = it.translated_offset;
689 ptr = ctx->data + offset;
691 g_assert (offset != INVALID_OFFSET);
693 if (read16 (ptr) != 72)
694 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size %d must be 72", read16 (ptr)));
696 if (!bounds_check_virtual_address (ctx, read32 (ptr + 8), read32 (ptr + 12)))
697 ADD_ERROR (ctx, g_strdup_printf ("Invalid medatata section rva/size pair %x/%x", read32 (ptr + 8), read32 (ptr + 12)));
700 if (!read32 (ptr + 8) || !read32 (ptr + 12))
701 ADD_ERROR (ctx, g_strdup_printf ("Missing medatata section in the CLI header"));
703 if ((read32 (ptr + 16) & ~0x0001000B) != 0)
704 ADD_ERROR (ctx, g_strdup_printf ("Invalid CLI header flags"));
707 for (i = 0; i < 6; ++i) {
708 guint32 rva = read32 (ptr);
709 guint32 size = read32 (ptr + 4);
711 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
712 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli section %i rva/size pair %x/%x", i, rva, size));
717 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't support cli header section %d", i));
722 pad4 (guint32 offset)
724 if (offset & 0x3) //pad to the next 4 byte boundary
725 offset = (offset & ~0x3) + 4;
730 verify_metadata_header (VerifyContext *ctx)
733 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
737 offset = it.translated_offset;
738 ptr = ctx->data + offset;
739 g_assert (offset != INVALID_OFFSET);
741 //build a directory entry for the metadata root
743 it.rva = read32 (ptr);
745 it.size = read32 (ptr);
746 it.translated_offset = offset = translate_rva (ctx, it.rva);
748 ptr = ctx->data + offset;
749 g_assert (offset != INVALID_OFFSET);
752 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small %d (at least 20 bytes required for initial decoding)", it.size));
754 if (read32 (ptr) != 0x424A5342)
755 ADD_ERROR (ctx, g_strdup_printf ("Invalid metadata signature, expected 0x424A5342 but got %08x", read32 (ptr)));
757 offset = pad4 (offset + 16 + read32 (ptr + 12));
759 if (!bounds_check_datadir (&it, offset, 4))
760 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));
762 ptr = ctx->data + offset; //move to streams header
764 if (read16 (ptr + 2) < 3)
765 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section must have at least 3 streams (#~, #GUID and #Blob"));
770 for (i = 0; i < 5; ++i) {
771 guint32 stream_off, stream_size;
772 int string_size, stream_idx;
774 if (!bounds_check_datadir (&it, offset, 8))
775 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));
777 stream_off = it.translated_offset + read32 (ptr);
778 stream_size = read32 (ptr + 4);
780 if (!bounds_check_datadir (&it, stream_off, stream_size))
781 ADD_ERROR (ctx, g_strdup_printf ("Invalid stream header %d offset/size pair %x/%x", 0, stream_off, stream_size));
786 for (string_size = 0; string_size < 32; ++string_size) {
787 if (!bounds_check_datadir (&it, offset++, 1))
788 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small to decode stream header %d name", i));
789 if (!ptr [string_size])
793 if (ptr [string_size])
794 ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d name larger than 32 bytes", i));
796 if (!strncmp ("#Strings", ptr, 9))
797 stream_idx = STRINGS_STREAM;
798 else if (!strncmp ("#US", ptr, 4))
799 stream_idx = USER_STRINGS_STREAM;
800 else if (!strncmp ("#Blob", ptr, 6))
801 stream_idx = BLOB_STREAM;
802 else if (!strncmp ("#GUID", ptr, 6))
803 stream_idx = GUID_STREAM;
804 else if (!strncmp ("#~", ptr, 3))
805 stream_idx = TILDE_STREAM;
807 ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d invalid name %s", i, ptr));
809 if (ctx->metadata_streams [stream_idx].offset != 0)
810 ADD_ERROR (ctx, g_strdup_printf ("Duplicated metadata stream header %s", ptr));
812 ctx->metadata_streams [stream_idx].offset = stream_off;
813 ctx->metadata_streams [stream_idx].size = stream_size;
815 offset = pad4 (offset);
816 ptr = ctx->data + offset;
819 if (!ctx->metadata_streams [TILDE_STREAM].size)
820 ADD_ERROR (ctx, g_strdup_printf ("Metadata #~ stream missing"));
821 if (!ctx->metadata_streams [GUID_STREAM].size)
822 ADD_ERROR (ctx, g_strdup_printf ("Metadata guid stream missing"));
823 if (!ctx->metadata_streams [BLOB_STREAM].size)
824 ADD_ERROR (ctx, g_strdup_printf ("Metadata blob stream missing"));
829 verify_tables_schema (VerifyContext *ctx)
831 OffsetAndSize tables_area = ctx->metadata_streams [TILDE_STREAM];
832 unsigned offset = tables_area.offset;
833 const char *ptr = ctx->data + offset;
834 guint64 valid_tables;
838 //printf ("tables_area size %d offset %x %s\n", tables_area.size, tables_area.offset, ctx->image->name);
839 if (tables_area.size < 24)
840 ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for initial decoding (requires 24 bytes)", tables_area.size));
842 //printf ("ptr %x %x\n", ptr[4], ptr[5]);
843 if (ptr [4] != 2 && ptr [4] != 1)
844 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata major version %d, expected 2", ptr [4]));
846 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata minor version %d, expected 0", ptr [5]));
848 if ((ptr [6] & ~0x7) != 0)
849 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]));
851 valid_tables = read64 (ptr + 8);
853 for (i = 0; i < 64; ++i) {
854 if (!(valid_tables & ((guint64)1 << i)))
857 /*MS Extensions: 0x3 0x5 0x7 0x13 0x16
858 Unused: 0x1E 0x1F 0x2D-0x3F
859 We don't care about the MS extensions.*/
860 if (i == 0x3 || i == 0x5 || i == 0x7 || i == 0x13 || i == 0x16)
861 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifies doesn't support MS specific table %x", i));
862 if (i == 0x1E || i == 0x1F || i >= 0x2D)
863 ADD_ERROR (ctx, g_strdup_printf ("Invalid table %x", i));
867 if (tables_area.size < 24 + count * 4)
868 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));
871 for (i = 0; i < 64; ++i) {
872 if (valid_tables & ((guint64)1 << i)) {
873 guint32 row_count = read32 (ptr);
874 if (row_count > (1 << 24) - 1)
875 ADD_ERROR (ctx, g_strdup_printf ("Invalid Table %d row count: %d. Mono only supports 16777215 rows", i, row_count));
881 /*----------nothing from here on can use data_directory or metadata_streams ---*/
884 get_col_offset (VerifyContext *ctx, int table, int column)
886 guint32 bitfield = ctx->image->tables [table].size_bitfield;
890 offset += mono_metadata_table_size (bitfield, column);
896 get_col_size (VerifyContext *ctx, int table, int column)
898 return mono_metadata_table_size (ctx->image->tables [table].size_bitfield, column);
902 get_metadata_stream (VerifyContext *ctx, MonoStreamHeader *header)
905 res.offset = header->data - ctx->data;
906 res.size = header->size;
912 is_valid_string_full (VerifyContext *ctx, guint32 offset, gboolean allow_empty)
914 OffsetAndSize strings = get_metadata_stream (ctx, &ctx->image->heap_strings);
916 const char *data = ctx->data + strings.offset;
918 if (offset >= strings.size)
920 if (data + offset < data) //FIXME, use a generalized and smart unsigned add with overflow check and fix the whole thing
923 if (!mono_utf8_validate_and_len_with_bounds (data + offset, strings.size - offset, &length, NULL))
925 return allow_empty || length > 0;
929 is_valid_string (VerifyContext *ctx, guint32 offset)
931 return is_valid_string_full (ctx, offset, TRUE);
935 is_valid_non_empty_string (VerifyContext *ctx, guint32 offset)
937 return is_valid_string_full (ctx, offset, FALSE);
941 is_valid_guid (VerifyContext *ctx, guint32 offset)
943 OffsetAndSize guids = get_metadata_stream (ctx, &ctx->image->heap_guid);
944 return guids.size >= 8 && guids.size - 8 >= offset;
948 get_coded_index_token (int token_kind, guint32 coded_token)
950 guint32 bits = coded_index_desc [token_kind];
951 return coded_token >> bits;
955 get_coded_index_table (int kind, guint32 coded_token)
957 guint32 idx, bits = coded_index_desc [kind];
959 idx = coded_token & ((1 << bits) - 1);
960 return coded_index_desc [kind + idx];
964 make_coded_token (int kind, guint32 table, guint32 table_idx)
966 guint32 bits = coded_index_desc [kind++];
967 guint32 tables = coded_index_desc [kind++];
969 for (i = 0; i < tables; ++i) {
970 if (coded_index_desc [kind++] == table)
971 return ((table_idx + 1) << bits) | i;
973 g_assert_not_reached ();
978 is_valid_coded_index (VerifyContext *ctx, int token_kind, guint32 coded_token)
980 guint32 bits = coded_index_desc [token_kind++];
981 guint32 table_count = coded_index_desc [token_kind++];
982 guint32 table = coded_token & ((1 << bits) - 1);
983 guint32 token = coded_token >> bits;
985 if (table >= table_count)
988 /*token_kind points to the first table idx*/
989 table = coded_index_desc [token_kind + table];
991 if (table == INVALID_TABLE)
993 return token <= ctx->image->tables [table].rows;
1000 MonoTableInfo *table;
1004 token_locator (const void *a, const void *b)
1006 RowLocator *loc = (RowLocator *)a;
1007 unsigned const char *row = (unsigned const char *)b;
1008 guint32 token = loc->col_size == 2 ? read16 (row + loc->col_offset) : read32 (row + loc->col_offset);
1010 VERIFIER_DEBUG ( printf ("\tfound token %x at idx %d\n", token, ((const char*)row - loc->table->base) / loc->table->row_size) );
1011 return (int)loc->token - (int)token;
1015 search_sorted_table (VerifyContext *ctx, int table, int column, guint32 coded_token)
1017 MonoTableInfo *tinfo = &ctx->image->tables [table];
1019 const char *res, *base;
1020 locator.token = coded_token;
1021 locator.col_offset = get_col_offset (ctx, table, column);
1022 locator.col_size = get_col_size (ctx, table, column);
1023 locator.table = tinfo;
1027 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) );
1028 res = bsearch (&locator, base, tinfo->rows, tinfo->row_size, token_locator);
1032 return (res - base) / tinfo->row_size;
1035 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1037 get_string_ptr (VerifyContext *ctx, guint offset)
1039 return ctx->image->heap_strings.data + offset;
1042 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1044 string_cmp (VerifyContext *ctx, const char *str, guint offset)
1047 return strcmp (str, "");
1049 return strcmp (str, get_string_ptr (ctx, offset));
1053 mono_verifier_is_corlib (MonoImage *image)
1055 gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ?
1056 TRUE : mono_security_core_clr_is_platform_image (image);
1058 return trusted_location && image->module_name && !strcmp ("mscorlib.dll", image->module_name);
1062 typedef_is_system_object (VerifyContext *ctx, guint32 *data)
1064 return mono_verifier_is_corlib (ctx->image) && !string_cmp (ctx, "System", data [MONO_TYPEDEF_NAMESPACE]) && !string_cmp (ctx, "Object", data [MONO_TYPEDEF_NAME]);
1068 decode_value (const char *_ptr, unsigned available, unsigned *value, unsigned *size)
1071 const unsigned char *ptr = (const unsigned char *)_ptr;
1079 if ((b & 0x80) == 0) {
1082 } else if ((b & 0x40) == 0) {
1086 *value = ((b & 0x3f) << 8 | ptr [1]);
1091 *value = ((b & 0x1f) << 24) |
1101 decode_signature_header (VerifyContext *ctx, guint32 offset, int *size, const char **first_byte)
1103 MonoStreamHeader blob = ctx->image->heap_blob;
1104 guint32 value, enc_size;
1106 if (offset >= blob.size)
1109 if (!decode_value (blob.data + offset, blob.size - offset, &value, &enc_size))
1112 if (offset + enc_size + value < offset)
1115 if (offset + enc_size + value > blob.size)
1119 *first_byte = blob.data + offset + enc_size;
1124 safe_read (const char **_ptr, const char *limit, void *dest, int size)
1126 const char *ptr = *_ptr;
1127 if (ptr + size > limit)
1131 *((guint8*)dest) = *((guint8*)ptr);
1135 *((guint16*)dest) = read16 (ptr);
1139 *((guint32*)dest) = read32 (ptr);
1148 safe_read_compressed_int (const char **_ptr, const char *limit, unsigned *dest)
1151 const char *ptr = *_ptr;
1152 gboolean res = decode_value (ptr, limit - ptr, dest, &size);
1157 #define safe_read8(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 1)
1158 #define safe_read_cint(VAR, PTR, LIMIT) safe_read_compressed_int (&PTR, LIMIT, &VAR)
1159 #define safe_read16(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 2)
1160 #define safe_read32(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 4)
1163 parse_type (VerifyContext *ctx, const char **_ptr, const char *end);
1166 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged);
1169 parse_custom_mods (VerifyContext *ctx, const char **_ptr, const char *end)
1171 const char *ptr = *_ptr;
1176 if (!safe_read8 (type, ptr, end))
1177 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the type"));
1179 if (type != MONO_TYPE_CMOD_REQD && type != MONO_TYPE_CMOD_OPT) {
1184 if (!safe_read_cint (token, ptr, end))
1185 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the token"));
1187 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1188 FAIL (ctx, g_strdup_printf ("CustomMod: invalid TypeDefOrRef token %x", token));
1196 parse_array_shape (VerifyContext *ctx, const char **_ptr, const char *end)
1198 const char *ptr = *_ptr;
1200 guint32 size, num, i;
1202 if (!safe_read8 (val, ptr, end))
1203 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for Rank"));
1206 FAIL (ctx, g_strdup ("ArrayShape: Invalid shape with zero Rank"));
1208 if (!safe_read_cint (size, ptr, end))
1209 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumSizes"));
1211 for (i = 0; i < size; ++i) {
1212 if (!safe_read_cint (num, ptr, end))
1213 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for Size of rank %d", i + 1));
1216 if (!safe_read_cint (size, ptr, end))
1217 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumLoBounds"));
1219 for (i = 0; i < size; ++i) {
1220 if (!safe_read_cint (num, ptr, end))
1221 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for LoBound of rank %d", i + 1));
1229 parse_generic_inst (VerifyContext *ctx, const char **_ptr, const char *end)
1231 const char *ptr = *_ptr;
1233 guint32 count, token, i;
1235 if (!safe_read8 (type, ptr, end))
1236 FAIL (ctx, g_strdup ("GenericInst: Not enough room for kind"));
1238 if (type != MONO_TYPE_CLASS && type != MONO_TYPE_VALUETYPE)
1239 FAIL (ctx, g_strdup_printf ("GenericInst: Invalid GenericInst kind %x\n", type));
1241 if (!safe_read_cint (token, ptr, end))
1242 FAIL (ctx, g_strdup ("GenericInst: Not enough room for type token"));
1244 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1245 FAIL (ctx, g_strdup_printf ("GenericInst: invalid TypeDefOrRef token %x", token));
1247 if (!safe_read_cint (count, ptr, end))
1248 FAIL (ctx, g_strdup ("GenericInst: Not enough room for argument count"));
1251 FAIL (ctx, g_strdup ("GenericInst: Zero arguments generic instance"));
1253 for (i = 0; i < count; ++i) {
1254 if (!parse_type (ctx, &ptr, end))
1255 FAIL (ctx, g_strdup_printf ("GenericInst: invalid generic argument %d", i + 1));
1262 parse_type (VerifyContext *ctx, const char **_ptr, const char *end)
1264 const char *ptr = *_ptr;
1268 if (!safe_read8 (type, ptr, end))
1269 FAIL (ctx, g_strdup ("Type: Not enough room for the type"));
1271 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_PTR) ||
1272 (type >= MONO_TYPE_VALUETYPE && type <= MONO_TYPE_GENERICINST) ||
1273 (type >= MONO_TYPE_I && type <= MONO_TYPE_U) ||
1274 (type >= MONO_TYPE_FNPTR && type <= MONO_TYPE_MVAR)))
1275 FAIL (ctx, g_strdup_printf ("Type: Invalid type kind %x\n", type));
1279 if (!parse_custom_mods (ctx, &ptr, end))
1280 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1282 if (!safe_read8 (type, ptr, end))
1283 FAIL (ctx, g_strdup ("Type: Not enough room to parse the pointer type"));
1285 if (type != MONO_TYPE_VOID) {
1287 if (!parse_type (ctx, &ptr, end))
1288 FAIL (ctx, g_strdup ("Type: Could not parse pointer type"));
1292 case MONO_TYPE_VALUETYPE:
1293 case MONO_TYPE_CLASS:
1294 if (!safe_read_cint (token, ptr, end))
1295 FAIL (ctx, g_strdup ("Type: Not enough room for the type token"));
1297 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1298 FAIL (ctx, g_strdup_printf ("Type: invalid TypeDefOrRef token %x", token));
1302 case MONO_TYPE_MVAR:
1303 if (!safe_read_cint (token, ptr, end))
1304 FAIL (ctx, g_strdup ("Type: Not enough room for to decode generic argument number"));
1307 case MONO_TYPE_ARRAY:
1308 if (!parse_type (ctx, &ptr, end))
1309 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1310 if (!parse_array_shape (ctx, &ptr, end))
1311 FAIL (ctx, g_strdup ("Type: Could not parse array shape"));
1314 case MONO_TYPE_GENERICINST:
1315 if (!parse_generic_inst (ctx, &ptr, end))
1316 FAIL (ctx, g_strdup ("Type: Could not parse generic inst"));
1319 case MONO_TYPE_FNPTR:
1320 if (!parse_method_signature (ctx, &ptr, end, TRUE, TRUE))
1321 FAIL (ctx, g_strdup ("Type: Could not parse method pointer signature"));
1324 case MONO_TYPE_SZARRAY:
1325 if (!parse_custom_mods (ctx, &ptr, end))
1326 FAIL (ctx, g_strdup ("Type: Failed to parse array element custom attr"));
1327 if (!parse_type (ctx, &ptr, end))
1328 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1336 parse_return_type (VerifyContext *ctx, const char **_ptr, const char *end)
1341 if (!parse_custom_mods (ctx, _ptr, end))
1345 if (!safe_read8 (type, ptr, end))
1346 FAIL (ctx, g_strdup ("ReturnType: Not enough room for the type"));
1348 if (type == MONO_TYPE_VOID || type == MONO_TYPE_TYPEDBYREF) {
1353 //it's a byref, update the cursor ptr
1354 if (type == MONO_TYPE_BYREF)
1357 return parse_type (ctx, _ptr, end);
1361 parse_param (VerifyContext *ctx, const char **_ptr, const char *end)
1366 if (!parse_custom_mods (ctx, _ptr, end))
1370 if (!safe_read8 (type, ptr, end))
1371 FAIL (ctx, g_strdup ("Param: Not enough room for the type"));
1373 if (type == MONO_TYPE_TYPEDBYREF) {
1378 //it's a byref, update the cursor ptr
1379 if (type == MONO_TYPE_BYREF)
1382 return parse_type (ctx, _ptr, end);
1386 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged)
1389 unsigned param_count = 0, gparam_count = 0, type = 0, i;
1390 const char *ptr = *_ptr;
1391 gboolean saw_sentinel = FALSE;
1393 if (!safe_read8 (cconv, ptr, end))
1394 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the call conv"));
1397 FAIL (ctx, g_strdup ("MethodSig: CallConv has 0x80 set"));
1399 if (allow_unmanaged) {
1400 if ((cconv & 0x0F) > MONO_CALL_VARARG)
1401 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not valid, it's %x", cconv & 0x0F));
1402 } else if ((cconv & 0x0F) != MONO_CALL_DEFAULT && (cconv & 0x0F) != MONO_CALL_VARARG)
1403 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not Default or Vararg, it's %x", cconv & 0x0F));
1405 if ((cconv & 0x10) && !safe_read_cint (gparam_count, ptr, end))
1406 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the generic param count"));
1408 if ((cconv & 0x10) && gparam_count == 0)
1409 FAIL (ctx, g_strdup ("MethodSig: Signature with generics but zero arity"));
1411 if (allow_unmanaged && (cconv & 0x10))
1412 FAIL (ctx, g_strdup ("MethodSig: Standalone signature with generic params"));
1414 if (!safe_read_cint (param_count, ptr, end))
1415 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the param count"));
1417 if (!parse_return_type (ctx, &ptr, end))
1418 FAIL (ctx, g_strdup ("MethodSig: Error parsing return type"));
1420 for (i = 0; i < param_count; ++i) {
1421 if (allow_sentinel) {
1422 if (!safe_read8 (type, ptr, end))
1423 FAIL (ctx, g_strdup_printf ("MethodSig: Not enough room for param %d type", i));
1425 if (type == MONO_TYPE_SENTINEL) {
1426 if ((cconv & 0x0F) != MONO_CALL_VARARG)
1427 FAIL (ctx, g_strdup ("MethodSig: Found sentinel but signature is not vararg"));
1430 FAIL (ctx, g_strdup ("MethodSig: More than one sentinel type"));
1432 saw_sentinel = TRUE;
1438 if (!parse_param (ctx, &ptr, end))
1439 FAIL (ctx, g_strdup_printf ("MethodSig: Error parsing arg %d", i));
1447 parse_property_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1450 unsigned param_count = 0, i;
1451 const char *ptr = *_ptr;
1453 if (!safe_read8 (sig, ptr, end))
1454 FAIL (ctx, g_strdup ("PropertySig: Not enough room for signature"));
1456 if (sig != 0x08 && sig != 0x28)
1457 FAIL (ctx, g_strdup_printf ("PropertySig: Signature is not 0x28 or 0x08: %x", sig));
1459 if (!safe_read_cint (param_count, ptr, end))
1460 FAIL (ctx, g_strdup ("PropertySig: Not enough room for the param count"));
1462 if (!parse_custom_mods (ctx, &ptr, end))
1465 if (!parse_type (ctx, &ptr, end))
1466 FAIL (ctx, g_strdup ("PropertySig: Could not parse property type"));
1468 for (i = 0; i < param_count; ++i) {
1469 if (!parse_type (ctx, &ptr, end))
1470 FAIL (ctx, g_strdup_printf ("PropertySig: Error parsing arg %d", i));
1478 parse_field (VerifyContext *ctx, const char **_ptr, const char *end)
1480 const char *ptr = *_ptr;
1481 guint8 signature = 0;
1483 if (!safe_read8 (signature, ptr, end))
1484 FAIL (ctx, g_strdup ("Field: Not enough room for field signature"));
1486 if (signature != 0x06)
1487 FAIL (ctx, g_strdup_printf ("Field: Invalid signature 0x%x, must be 6", signature));
1490 if (!parse_custom_mods (ctx, _ptr, end))
1493 return parse_type (ctx, _ptr, end);
1497 parse_locals_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1500 unsigned locals_count = 0, i;
1501 const char *ptr = *_ptr;
1503 if (!safe_read8 (sig, ptr, end))
1504 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for signature"));
1507 FAIL (ctx, g_strdup_printf ("LocalsSig: Signature is not 0x28 or 0x08: %x", sig));
1509 if (!safe_read_cint (locals_count, ptr, end))
1510 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for the param count"));
1512 if (locals_count == 0)
1513 FAIL (ctx, g_strdup ("LocalsSig: Signature with zero locals"));
1515 for (i = 0; i < locals_count; ++i) {
1516 if (!safe_read8 (sig, ptr, end))
1517 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1519 if (sig == MONO_TYPE_TYPEDBYREF)
1522 while (sig == MONO_TYPE_CMOD_REQD || sig == MONO_TYPE_CMOD_OPT || sig == MONO_TYPE_PINNED) {
1523 if (sig != MONO_TYPE_PINNED && !parse_custom_mods (ctx, &ptr, end))
1524 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1525 if (!safe_read8 (sig, ptr, end))
1526 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1529 if (!parse_type (ctx, &ptr, end))
1530 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1538 is_valid_field_signature (VerifyContext *ctx, guint32 offset)
1540 int size = 0, signature = 0;
1541 const char *ptr = NULL, *end;
1543 if (!decode_signature_header (ctx, offset, &size, &ptr))
1544 FAIL (ctx, g_strdup ("FieldSig: Could not decode signature header"));
1547 if (!safe_read8 (signature, ptr, end))
1548 FAIL (ctx, g_strdup ("FieldSig: Not enough room for the signature"));
1551 FAIL (ctx, g_strdup_printf ("FieldSig: Invalid signature %x", signature));
1554 return parse_field (ctx, &ptr, end);
1558 is_valid_method_signature (VerifyContext *ctx, guint32 offset)
1561 const char *ptr = NULL, *end;
1563 if (!decode_signature_header (ctx, offset, &size, &ptr))
1564 FAIL (ctx, g_strdup ("MethodSig: Could not decode signature header"));
1567 return parse_method_signature (ctx, &ptr, end, FALSE, FALSE);
1571 is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
1574 unsigned signature = 0;
1575 const char *ptr = NULL, *end;
1577 if (!decode_signature_header (ctx, offset, &size, &ptr))
1578 FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
1581 if (!safe_read8 (signature, ptr, end))
1582 FAIL (ctx, g_strdup ("MemberRefSig: Not enough room for the call conv"));
1585 if (signature == 0x06)
1586 return parse_field (ctx, &ptr, end);
1588 return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1592 is_vald_cattr_blob (VerifyContext *ctx, guint32 offset)
1596 const char *ptr = NULL, *end;
1601 if (!decode_signature_header (ctx, offset, &size, &ptr))
1602 FAIL (ctx, g_strdup ("CustomAttribute: Could not decode signature header"));
1605 if (!safe_read16 (prolog, ptr, end))
1606 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1609 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1615 is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
1617 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1618 //TODO do proper verification
1619 return blob.size >= 1 && blob.size - 1 >= offset;
1623 is_valid_permission_set (VerifyContext *ctx, guint32 offset)
1625 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1626 //TODO do proper verification
1627 return blob.size >= 1 && blob.size - 1 >= offset;
1631 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
1634 unsigned signature = 0;
1635 const char *ptr = NULL, *end;
1637 if (!decode_signature_header (ctx, offset, &size, &ptr))
1638 FAIL (ctx, g_strdup ("StandAloneSig: Could not decode signature header"));
1641 if (!safe_read8 (signature, ptr, end))
1642 FAIL (ctx, g_strdup ("StandAloneSig: Not enough room for the call conv"));
1645 if (signature == 0x07)
1646 return parse_locals_signature (ctx, &ptr, end);
1647 return parse_method_signature (ctx, &ptr, end, TRUE, TRUE);
1651 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
1654 const char *ptr = NULL, *end;
1656 if (!decode_signature_header (ctx, offset, &size, &ptr))
1657 FAIL (ctx, g_strdup ("PropertySig: Could not decode signature header"));
1660 return parse_property_signature (ctx, &ptr, end);
1664 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
1667 const char *ptr = NULL, *end;
1671 if (!decode_signature_header (ctx, offset, &size, &ptr))
1672 FAIL (ctx, g_strdup ("TypeSpec: Could not decode signature header"));
1675 if (!parse_custom_mods (ctx, &ptr, end))
1678 if (!safe_read8 (type, ptr, end))
1679 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for type"));
1682 if (type == MONO_TYPE_TYPEDBYREF)
1685 return parse_type (ctx, &ptr, end);
1689 is_valid_methodspec_blog (VerifyContext *ctx, guint32 offset)
1692 const char *ptr = NULL, *end;
1694 guint32 count = 0, i;
1696 if (!decode_signature_header (ctx, offset, &size, &ptr))
1697 FAIL (ctx, g_strdup ("MethodSpec: Could not decode signature header"));
1700 if (!safe_read8 (type, ptr, end))
1701 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for call convention"));
1704 FAIL (ctx, g_strdup_printf ("MethodSpec: Invalid call convention 0x%x, expected 0x0A", type));
1706 if (!safe_read_cint (count, ptr, end))
1707 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for parameter count"));
1710 FAIL (ctx, g_strdup ("MethodSpec: Zero generic argument count"));
1712 for (i = 0; i < count; ++i) {
1713 if (!parse_type (ctx, &ptr, end))
1714 FAIL (ctx, g_strdup_printf ("MethodSpec: Could not parse parameter %d", i + 1));
1720 is_valid_blob_object (VerifyContext *ctx, guint32 offset)
1722 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1723 guint32 entry_size, bytes;
1725 if (blob.size < offset)
1728 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1731 if (offset + entry_size + bytes < offset)
1734 return blob.size >= offset + entry_size + bytes;
1738 is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
1740 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1741 guint32 size, entry_size, bytes;
1743 if (blob.size < offset)
1746 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1749 if (type == MONO_TYPE_STRING) {
1750 //String is encoded as: compressed_int:len len *chars
1753 if (offset > offset + entry_size * 2) //overflow
1755 offset += offset + entry_size * 2;
1756 return offset <= blob.size;
1760 case MONO_TYPE_BOOLEAN:
1765 case MONO_TYPE_CHAR:
1773 case MONO_TYPE_CLASS:
1783 g_assert_not_reached ();
1786 if (size != entry_size)
1790 if(offset > offset + size) //overflow
1793 if (offset + size > blob.size)
1796 if (type == MONO_TYPE_CLASS && read32 (ctx->data + offset))
1801 #define FAT_HEADER_INVALID_FLAGS ~(0x3 | 0x8 | 0x10 | 0xF000)
1802 //only 0x01, 0x40 and 0x80 are allowed
1803 #define SECTION_HEADER_INVALID_FLAGS 0x3E
1806 is_valid_method_header (VerifyContext *ctx, guint32 rva)
1808 guint32 local_vars_tok, code_size, offset = mono_cli_rva_image_map (ctx->image, rva);
1810 guint16 fat_header = 0, size = 0, max_stack;
1811 const char *ptr = NULL, *end;
1813 if (offset == INVALID_ADDRESS)
1814 FAIL (ctx, g_strdup ("MethodHeader: Invalid RVA"));
1816 ptr = ctx->data + offset;
1817 end = ctx->data + ctx->size; /*no worries if it spawns multiple sections*/
1819 if (!safe_read8 (header, ptr, end))
1820 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for header"));
1822 switch (header & 0x3) {
1825 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid header type 0x%x", header & 0x3));
1828 if (ADDP_IS_GREATER_OR_OVF (ptr, header, end))
1829 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for method body. Required %d, but only %d is available", header, end - ptr));
1834 if (!safe_read16 (fat_header, ptr, end))
1835 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for fat header"));
1837 size = (fat_header >> 12) & 0xF;
1839 FAIL (ctx, g_strdup ("MethodHeader: header size must be 3"));
1841 if (!safe_read16 (max_stack, ptr, end))
1842 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for max stack"));
1844 if (!safe_read32 (code_size, ptr, end))
1845 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for code size"));
1847 if (!safe_read32 (local_vars_tok, ptr, end))
1848 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for local vars tok"));
1850 if (local_vars_tok) {
1851 if (((local_vars_tok >> 24) & 0xFF) != 0x11)
1852 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature table 0x%x", ((local_vars_tok >> 24) & 0xFF)));
1853 if ((local_vars_tok & 0xFFFFFF) > ctx->image->tables [MONO_TABLE_STANDALONESIG].rows)
1854 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature points to invalid row 0x%x", local_vars_tok & 0xFFFFFF));
1857 if (fat_header & FAT_HEADER_INVALID_FLAGS)
1858 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid fat signature flags %x", fat_header & FAT_HEADER_INVALID_FLAGS));
1860 if (ADDP_IS_GREATER_OR_OVF (ptr, code_size, end))
1861 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for code %d", code_size));
1863 if (!(fat_header & 0x08))
1869 guint32 section_header = 0, section_size = 0;
1872 ptr = dword_align (ptr);
1873 if (!safe_read32 (section_header, ptr, end))
1874 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for data section header"));
1876 if (section_header & SECTION_HEADER_INVALID_FLAGS)
1877 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section header flags 0x%x", section_header & SECTION_HEADER_INVALID_FLAGS));
1879 is_fat = (section_header & METHOD_HEADER_SECTION_FAT_FORMAT) != 0;
1880 section_size = (section_header >> 8) & (is_fat ? 0xFFFFFF : 0xFF);
1882 if (section_size < 4)
1883 FAIL (ctx, g_strdup_printf ("MethodHeader: Section size too small"));
1885 if (ADDP_IS_GREATER_OR_OVF (ptr, section_size - 4, end)) /*must be section_size -4 as ptr was incremented by safe_read32*/
1886 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section content %d", section_size));
1888 if (section_header & METHOD_HEADER_SECTION_EHTABLE) {
1889 guint32 i, clauses = (section_size - 4) / (is_fat ? 24 : 12);
1890 if (clauses * (is_fat ? 24 : 12) + 4 != section_size)
1891 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid EH section size %d, it's not of the proper size", section_size));
1893 /* only verify the class token is verified as the rest is done by the IL verifier*/
1894 for (i = 0; i < clauses; ++i) {
1895 guint32 class_token = 0;
1896 ptr += (is_fat ? 20 : 8);
1897 if (!safe_read32 (class_token, ptr, end))
1898 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section %d", i));
1899 if (!*ptr == MONO_EXCEPTION_CLAUSE_NONE && class_token) {
1900 guint table = mono_metadata_token_table (class_token);
1901 if (table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPESPEC)
1902 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token table %x", i, table));
1903 if (mono_metadata_token_index (class_token) > ctx->image->tables [table].rows)
1904 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token index %x", i, mono_metadata_token_index (class_token)));
1909 if (!(section_header & METHOD_HEADER_SECTION_MORE_SECTS))
1916 verify_module_table (VerifyContext *ctx)
1918 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
1919 guint32 data [MONO_MODULE_SIZE];
1921 if (table->rows != 1)
1922 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
1924 mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
1926 if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
1927 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
1929 if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
1930 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
1932 if (data [MONO_MODULE_ENC] != 0)
1933 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
1935 if (data [MONO_MODULE_ENCBASE] != 0)
1936 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
1940 verify_typeref_table (VerifyContext *ctx)
1942 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
1943 guint32 data [MONO_TYPEREF_SIZE];
1946 for (i = 0; i < table->rows; ++i) {
1947 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
1948 if (!is_valid_coded_index (ctx, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1949 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d coded index 0x%08x", i, data [MONO_TYPEREF_SCOPE]));
1951 if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1952 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", i));
1954 if (!data [MONO_TYPEREF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAME]))
1955 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d name token 0x%08x", i, data [MONO_TYPEREF_NAME]));
1957 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
1958 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d namespace token 0x%08x", i, data [MONO_TYPEREF_NAMESPACE]));
1962 /*bits 9,11,14,15,19,21,24-31 */
1963 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 14) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
1965 verify_typedef_table (VerifyContext *ctx)
1967 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
1968 guint32 data [MONO_TYPEDEF_SIZE];
1969 guint32 fieldlist = 1, methodlist = 1;
1972 if (table->rows == 0)
1973 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
1975 for (i = 0; i < table->rows; ++i) {
1976 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
1977 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
1978 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
1980 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
1981 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
1983 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
1984 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
1986 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
1987 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
1989 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
1990 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
1992 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
1993 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
1995 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
1996 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
1998 if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
1999 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
2001 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
2002 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));
2004 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
2005 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
2007 if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
2008 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
2010 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
2011 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));
2014 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
2015 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
2020 verify_typedef_table_full (VerifyContext *ctx)
2022 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2023 guint32 data [MONO_TYPEDEF_SIZE];
2026 if (table->rows == 0)
2027 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2029 for (i = 0; i < table->rows; ++i) {
2030 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2033 if (data [MONO_TYPEDEF_EXTENDS] != 0)
2034 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
2038 if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
2039 if (data [MONO_TYPEDEF_EXTENDS])
2040 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
2041 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
2042 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
2044 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
2045 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
2048 if (!(data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE)) {
2049 gboolean is_sys_obj = typedef_is_system_object (ctx, data);
2050 gboolean has_parent = get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]) != 0;
2054 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
2057 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
2065 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
2067 verify_field_table (VerifyContext *ctx)
2069 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2070 guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
2073 module_field_list = (guint32)-1;
2074 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2075 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2076 module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
2079 for (i = 0; i < table->rows; ++i) {
2080 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2081 flags = data [MONO_FIELD_FLAGS];
2083 if (flags & INVALID_FIELD_FLAG_BITS)
2084 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
2086 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)
2087 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
2089 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
2090 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
2092 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
2093 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
2095 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
2096 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
2098 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
2099 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
2100 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
2102 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
2103 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2104 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2106 if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
2107 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2108 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
2110 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
2111 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
2112 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2114 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
2115 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
2117 //TODO verify contant flag
2119 if (i + 1 < module_field_list) {
2120 guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
2121 if (!(flags & FIELD_ATTRIBUTE_STATIC))
2122 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
2123 if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
2124 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
2130 verify_field_table_full (VerifyContext *ctx)
2132 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2133 guint32 data [MONO_FIELD_SIZE];
2136 for (i = 0; i < table->rows; ++i) {
2137 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2139 if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
2140 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
2144 /*bits 6,8,9,10,11,13,14,15*/
2145 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 6) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
2147 verify_method_table (VerifyContext *ctx)
2149 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2150 guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
2151 guint32 paramlist = 1;
2152 gboolean is_ctor, is_cctor;
2156 module_method_list = (guint32)-1;
2157 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2158 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2159 module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
2162 for (i = 0; i < table->rows; ++i) {
2163 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2164 rva = data [MONO_METHOD_RVA];
2165 implflags = data [MONO_METHOD_IMPLFLAGS];
2166 flags = data [MONO_METHOD_FLAGS];
2167 access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
2168 code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
2171 if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
2172 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
2175 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
2177 if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
2178 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
2180 name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
2181 is_ctor = !strcmp (".ctor", name);
2182 is_cctor = !strcmp (".cctor", name);
2184 if ((is_ctor || is_cctor) &&
2185 search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
2186 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
2188 if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
2189 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
2191 if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
2192 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
2193 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
2194 if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
2195 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
2198 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
2199 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
2201 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
2202 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
2204 //XXX no checks against cas stuff 10,11,12,13)
2206 //TODO check iface with .ctor (15,16)
2208 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
2209 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
2211 if (i + 1 < module_method_list) {
2212 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2213 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
2214 if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
2215 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
2216 if (!(access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED || access == METHOD_ATTRIBUTE_PUBLIC || access == METHOD_ATTRIBUTE_PRIVATE))
2217 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public or Private", i));
2220 //TODO check valuetype for synchronized
2222 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
2223 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
2225 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && (flags & METHOD_ATTRIBUTE_VIRTUAL))
2226 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
2228 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
2229 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2230 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
2232 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
2233 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
2235 //TODO check signature contents
2238 if (flags & METHOD_ATTRIBUTE_ABSTRACT)
2239 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", i));
2240 if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
2241 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
2243 if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2244 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
2247 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2249 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
2250 if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
2251 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
2253 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
2254 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
2256 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
2257 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
2259 if (data [MONO_METHOD_PARAMLIST] == 0)
2260 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
2262 if (data [MONO_METHOD_PARAMLIST] < paramlist)
2263 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));
2265 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
2266 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
2268 paramlist = data [MONO_METHOD_PARAMLIST];
2274 verify_method_table_full (VerifyContext *ctx)
2276 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2277 guint32 data [MONO_METHOD_SIZE], rva;
2280 for (i = 0; i < table->rows; ++i) {
2281 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2282 rva = data [MONO_METHOD_RVA];
2284 if (rva && !is_valid_method_header (ctx, rva))
2285 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
2290 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
2292 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2293 guint32 row = *current_method;
2294 guint32 paramlist, tmp;
2297 paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
2298 while (row < table->rows) {
2299 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
2300 if (tmp > paramlist) {
2301 *current_method = row;
2302 return tmp - paramlist;
2307 /*no more methods, all params apply to the last one*/
2308 *current_method = table->rows;
2313 #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))
2315 verify_param_table (VerifyContext *ctx)
2317 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
2318 guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
2319 gboolean first_param = TRUE;
2322 remaining_params = get_next_param_count (ctx, ¤t_method);
2324 for (i = 0; i < table->rows; ++i) {
2325 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
2326 flags = data [MONO_PARAM_FLAGS];
2328 if (flags & INVALID_PARAM_FLAGS_BITS)
2329 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
2331 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
2332 if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
2333 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
2335 if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
2336 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
2339 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)
2340 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
2342 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
2343 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
2345 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
2346 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
2348 first_param = FALSE;
2349 sequence = data [MONO_PARAM_SEQUENCE];
2350 if (--remaining_params == 0) {
2351 remaining_params = get_next_param_count (ctx, ¤t_method);
2358 verify_interfaceimpl_table (VerifyContext *ctx)
2360 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
2361 guint32 data [MONO_INTERFACEIMPL_SIZE];
2364 for (i = 0; i < table->rows; ++i) {
2365 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
2366 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2367 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2369 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2370 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
2372 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2373 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
2378 verify_memberref_table (VerifyContext *ctx)
2380 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2381 guint32 data [MONO_MEMBERREF_SIZE];
2384 for (i = 0; i < table->rows; ++i) {
2385 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2387 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2388 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
2390 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2391 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
2393 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
2394 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
2400 verify_memberref_table_full (VerifyContext *ctx)
2402 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2403 guint32 data [MONO_MEMBERREF_SIZE];
2406 for (i = 0; i < table->rows; ++i) {
2407 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2409 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
2410 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field 0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
2415 verify_constant_table (VerifyContext *ctx)
2417 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
2418 guint32 data [MONO_CONSTANT_SIZE], type;
2421 for (i = 0; i < table->rows; ++i) {
2422 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
2423 type = data [MONO_CONSTANT_TYPE];
2425 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
2426 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
2428 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2429 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
2431 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2432 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
2434 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
2435 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
2440 verify_cattr_table (VerifyContext *ctx)
2442 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2443 guint32 data [MONO_CUSTOM_ATTR_SIZE];
2446 for (i = 0; i < table->rows; ++i) {
2447 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2449 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
2450 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2452 if (!is_valid_coded_index (ctx, CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]))
2453 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2458 verify_cattr_table_full (VerifyContext *ctx)
2460 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2461 guint32 data [MONO_CUSTOM_ATTR_SIZE];
2464 for (i = 0; i < table->rows; ++i) {
2465 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2467 if (!is_vald_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
2468 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2473 verify_field_marshal_table (VerifyContext *ctx)
2475 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2476 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2479 for (i = 0; i < table->rows; ++i) {
2480 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2482 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2483 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
2485 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2486 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
2488 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
2489 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
2494 verify_field_marshal_table_full (VerifyContext *ctx)
2496 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2497 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2500 for (i = 0; i < table->rows; ++i) {
2501 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2503 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
2504 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2509 verify_decl_security_table (VerifyContext *ctx)
2511 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2512 guint32 data [MONO_DECL_SECURITY_SIZE];
2515 for (i = 0; i < table->rows; ++i) {
2516 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2518 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2519 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
2521 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2522 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
2524 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
2525 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
2530 verify_decl_security_table_full (VerifyContext *ctx)
2532 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2533 guint32 data [MONO_DECL_SECURITY_SIZE];
2536 for (i = 0; i < table->rows; ++i) {
2537 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2539 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
2540 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
2545 verify_class_layout_table (VerifyContext *ctx)
2547 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
2548 guint32 data [MONO_CLASS_LAYOUT_SIZE];
2551 for (i = 0; i < table->rows; ++i) {
2552 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
2554 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2555 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2557 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
2569 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
2575 verify_field_layout_table (VerifyContext *ctx)
2577 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
2578 guint32 data [MONO_FIELD_LAYOUT_SIZE];
2581 for (i = 0; i < table->rows; ++i) {
2582 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
2584 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2585 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
2590 verify_standalonesig_table_full (VerifyContext *ctx)
2592 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
2593 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
2596 for (i = 0; i < table->rows; ++i) {
2597 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
2599 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
2600 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
2605 verify_eventmap_table (VerifyContext *ctx)
2607 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
2608 guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
2611 for (i = 0; i < table->rows; ++i) {
2612 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
2614 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2615 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
2617 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
2618 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
2620 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
2624 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
2626 verify_event_table (VerifyContext *ctx)
2628 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
2629 MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
2630 guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
2631 gboolean found_add, found_remove;
2634 for (i = 0; i < table->rows; ++i) {
2635 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
2637 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
2638 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
2640 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
2641 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
2643 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
2644 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
2646 //check for Add and Remove
2647 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
2648 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
2650 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
2652 //first we move to the first row for this event
2654 if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
2658 //now move forward looking for AddOn and RemoveOn rows
2659 found_add = found_remove = FALSE;
2660 while (idx < sema_table->rows) {
2661 mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
2662 if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
2664 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
2666 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
2667 found_remove = TRUE;
2668 if (found_add && found_remove)
2674 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2676 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2681 verify_propertymap_table (VerifyContext *ctx)
2683 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
2684 guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
2687 for (i = 0; i < table->rows; ++i) {
2688 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
2690 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2691 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
2693 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
2694 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
2696 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
2700 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
2702 verify_property_table (VerifyContext *ctx)
2704 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
2705 guint32 data [MONO_PROPERTY_SIZE];
2708 for (i = 0; i < table->rows; ++i) {
2709 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
2711 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
2712 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
2714 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
2715 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
2717 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
2718 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
2720 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
2721 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
2722 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
2728 verify_methodimpl_table (VerifyContext *ctx)
2730 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
2731 guint32 data [MONO_METHODIMPL_SIZE];
2734 for (i = 0; i < table->rows; ++i) {
2735 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
2737 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2738 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2740 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2741 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2743 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2744 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2746 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2747 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2749 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2750 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2755 verify_moduleref_table (VerifyContext *ctx)
2757 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
2758 guint32 data [MONO_MODULEREF_SIZE];
2761 for (i = 0; i < table->rows; ++i) {
2762 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
2764 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
2765 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2770 verify_typespec_table (VerifyContext *ctx)
2772 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
2773 guint32 data [MONO_TYPESPEC_SIZE];
2776 for (i = 0; i < table->rows; ++i) {
2777 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
2779 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
2780 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
2784 #define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 6) | (1 << 8) | (1 << 9) | (1 << 10))
2786 verify_implmap_table (VerifyContext *ctx)
2788 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
2789 guint32 data [MONO_IMPLMAP_SIZE], cconv;
2792 for (i = 0; i < table->rows; ++i) {
2793 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
2795 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
2796 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
2798 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
2799 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
2800 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
2802 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2803 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
2805 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
2806 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
2808 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2809 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
2811 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
2812 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
2814 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULEREF].rows + 1)
2815 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
2820 verify_fieldrva_table (VerifyContext *ctx)
2822 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
2823 guint32 data [MONO_FIELD_RVA_SIZE];
2826 for (i = 0; i < table->rows; ++i) {
2827 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
2829 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
2830 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
2832 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2833 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
2837 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 8) | (1 << 14) | (1 << 15))
2839 verify_assembly_table (VerifyContext *ctx)
2841 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
2842 guint32 data [MONO_ASSEMBLY_SIZE], hash;
2845 if (table->rows > 1)
2846 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
2848 for (i = 0; i < table->rows; ++i) {
2849 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
2851 hash = data [MONO_ASSEMBLY_HASH_ALG];
2852 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
2853 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
2855 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
2856 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2858 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY]))
2859 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2861 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
2862 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
2864 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
2865 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
2869 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~(1)
2871 verify_assemblyref_table (VerifyContext *ctx)
2873 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
2874 guint32 data [MONO_ASSEMBLYREF_SIZE];
2877 for (i = 0; i < table->rows; ++i) {
2878 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
2880 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
2881 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
2883 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY]))
2884 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
2886 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
2887 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
2889 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
2890 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
2892 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE]))
2893 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
2897 #define INVALID_FILE_FLAGS_BITS ~(1)
2899 verify_file_table (VerifyContext *ctx)
2901 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
2902 guint32 data [MONO_FILE_SIZE];
2905 for (i = 0; i < table->rows; ++i) {
2906 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
2908 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
2909 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
2911 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
2912 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
2914 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE]))
2915 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
2919 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
2921 verify_exportedtype_table (VerifyContext *ctx)
2923 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
2924 guint32 data [MONO_EXP_TYPE_SIZE];
2927 for (i = 0; i < table->rows; ++i) {
2928 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
2930 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
2931 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
2933 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
2934 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
2936 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
2937 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
2939 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
2940 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
2942 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
2943 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
2945 /*nested type can't have a namespace*/
2946 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
2947 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
2951 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
2953 verify_manifest_resource_table (VerifyContext *ctx)
2955 MonoCLIImageInfo *iinfo = ctx->image->image_info;
2956 MonoCLIHeader *ch = &iinfo->cli_cli_header;
2957 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
2958 guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
2961 resources_size = ch->ch_resources.size;
2963 for (i = 0; i < table->rows; ++i) {
2964 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
2966 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
2967 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
2969 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
2970 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
2972 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
2973 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
2975 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
2976 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
2978 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
2979 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
2981 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
2982 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])));
2984 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
2985 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
2987 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
2988 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
2993 verify_nested_class_table (VerifyContext *ctx)
2995 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
2996 guint32 data [MONO_NESTED_CLASS_SIZE];
2999 for (i = 0; i < table->rows; ++i) {
3000 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
3002 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3003 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
3004 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3005 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3006 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
3007 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3011 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
3013 verify_generic_param_table (VerifyContext *ctx)
3015 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
3016 guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
3017 int i, param_number = 0;
3019 for (i = 0; i < table->rows; ++i) {
3020 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
3022 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
3023 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
3025 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
3026 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
3028 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
3029 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
3031 token = data [MONO_GENERICPARAM_OWNER];
3033 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
3034 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
3036 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
3037 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
3039 if (token != last_token) {
3044 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
3045 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));
3052 verify_method_spec_table (VerifyContext *ctx)
3054 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3055 guint32 data [MONO_METHODSPEC_SIZE];
3058 for (i = 0; i < table->rows; ++i) {
3059 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3061 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3062 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
3064 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3065 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
3067 if (!is_valid_methodspec_blog (ctx, data [MONO_METHODSPEC_SIGNATURE]))
3068 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3073 verify_generic_param_constraint_table (VerifyContext *ctx)
3075 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
3076 guint32 data [MONO_GENPARCONSTRAINT_SIZE];
3079 for (i = 0; i < table->rows; ++i) {
3080 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
3082 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
3083 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_TABLE_GENERICPARAM]));
3085 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3086 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
3088 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3089 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
3094 verify_tables_data (VerifyContext *ctx)
3096 OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
3097 guint32 size = 0, tables_offset;
3100 for (i = 0; i < 0x2D; ++i) {
3101 MonoTableInfo *table = &ctx->image->tables [i];
3103 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
3104 if (tmp_size < size) {
3112 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
3114 tables_offset = ctx->image->tables_base - ctx->data;
3115 if (!bounds_check_offset (&tables_area, tables_offset, size))
3116 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)));
3118 verify_module_table (ctx);
3120 verify_typeref_table (ctx);
3122 verify_typedef_table (ctx);
3124 verify_field_table (ctx);
3126 verify_method_table (ctx);
3128 verify_param_table (ctx);
3130 verify_interfaceimpl_table (ctx);
3132 verify_memberref_table (ctx);
3134 verify_constant_table (ctx);
3136 verify_cattr_table (ctx);
3138 verify_field_marshal_table (ctx);
3140 verify_decl_security_table (ctx);
3142 verify_class_layout_table (ctx);
3144 verify_field_layout_table (ctx);
3146 verify_eventmap_table (ctx);
3148 verify_event_table (ctx);
3150 verify_propertymap_table (ctx);
3152 verify_property_table (ctx);
3154 verify_methodimpl_table (ctx);
3156 verify_moduleref_table (ctx);
3158 verify_typespec_table (ctx);
3160 verify_implmap_table (ctx);
3162 verify_fieldrva_table (ctx);
3164 verify_assembly_table (ctx);
3166 verify_assemblyref_table (ctx);
3168 verify_file_table (ctx);
3170 verify_exportedtype_table (ctx);
3172 verify_manifest_resource_table (ctx);
3174 verify_nested_class_table (ctx);
3176 verify_generic_param_table (ctx);
3178 verify_method_spec_table (ctx);
3180 verify_generic_param_constraint_table (ctx);
3184 init_verify_context (VerifyContext *ctx, MonoImage *image, GSList **error_list)
3186 memset (ctx, 0, sizeof (VerifyContext));
3188 ctx->report_error = error_list != NULL;
3190 ctx->size = image->raw_data_len;
3191 ctx->data = image->raw_data;
3195 cleanup_context (VerifyContext *ctx, GSList **error_list)
3197 g_free (ctx->sections);
3199 *error_list = ctx->errors;
3201 mono_free_verify_list (ctx->errors);
3206 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3210 if (!mono_verifier_is_enabled_for_image (image))
3213 init_verify_context (&ctx, image, error_list);
3214 ctx.stage = STAGE_PE;
3216 verify_msdos_header (&ctx);
3218 verify_pe_header (&ctx);
3220 verify_pe_optional_header (&ctx);
3222 load_section_table (&ctx);
3224 load_data_directories (&ctx);
3226 verify_import_table (&ctx);
3228 /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
3229 verify_resources_table (&ctx);
3232 return cleanup_context (&ctx, error_list);
3236 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3240 if (!mono_verifier_is_enabled_for_image (image))
3243 init_verify_context (&ctx, image, error_list);
3244 ctx.stage = STAGE_CLI;
3246 verify_cli_header (&ctx);
3248 verify_metadata_header (&ctx);
3250 verify_tables_schema (&ctx);
3253 return cleanup_context (&ctx, error_list);
3258 * Verifies basic table constraints such as global table invariants (sorting, field monotonicity, etc).
3259 * Other verification checks are meant to be done lazily by the runtime. Those include:
3260 * blob items (signatures, method headers, custom attributes, etc)
3261 * type semantics related
3263 * stuff that should not block other pieces from running such as bad types/methods/fields/etc.
3265 * The whole idea is that if this succeed the runtime is free to play around safely but any complex
3266 * operation still need more checking.
3269 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3273 if (!mono_verifier_is_enabled_for_image (image))
3276 init_verify_context (&ctx, image, error_list);
3277 ctx.stage = STAGE_TABLES;
3279 verify_tables_data (&ctx);
3281 return cleanup_context (&ctx, error_list);
3286 * Verifies all other constraints.
3289 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3293 if (!mono_verifier_is_enabled_for_image (image))
3296 init_verify_context (&ctx, image, error_list);
3297 ctx.stage = STAGE_TABLES;
3299 verify_typedef_table_full (&ctx);
3301 verify_field_table_full (&ctx);
3303 verify_method_table_full (&ctx);
3305 verify_memberref_table_full (&ctx);
3307 verify_cattr_table_full (&ctx);
3309 verify_field_marshal_table_full (&ctx);
3311 verify_decl_security_table_full (&ctx);
3313 verify_standalonesig_table_full (&ctx);
3316 return cleanup_context (&ctx, error_list);
3321 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3327 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3333 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3339 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3344 #endif /* DISABLE_VERIFIER */