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>
26 #include <mono/utils/mono-error-internals.h>
31 #ifndef DISABLE_VERIFIER
33 TODO add fail fast mode
34 TODO add PE32+ support
35 TODO verify the entry point RVA and content.
36 TODO load_section_table and load_data_directories must take PE32+ into account
37 TODO add section relocation support
38 TODO verify the relocation table, since we really don't use, no need so far.
39 TODO do full PECOFF resources verification
40 TODO verify in the CLI header entry point and resources
41 TODO implement null token typeref validation
42 TODO verify table wide invariants for typedef (sorting and uniqueness)
43 TODO implement proper authenticode data directory validation
44 TODO verify properties that require multiple tables to be valid
45 FIXME use subtraction based bounds checking to avoid overflows
46 FIXME get rid of metadata_streams and other fields from VerifyContext
49 #ifdef MONO_VERIFIER_DEBUG
50 #define VERIFIER_DEBUG(code) do { code; } while (0)
52 #define VERIFIER_DEBUG(code)
55 #define INVALID_OFFSET ((guint32)-1)
56 #define INVALID_ADDRESS 0xffffffff
66 RESOURCE_TABLE_IDX = 2,
67 CERTIFICATE_TABLE_IDX = 4,
68 RELOCATION_TABLE_IDX = 5,
82 #define INVALID_TABLE (0xFF)
83 /*format: number of bits, number of tables, tables{n. tables} */
84 const static unsigned char coded_index_desc[] = {
85 #define TYPEDEF_OR_REF_DESC (0)
92 #define HAS_CONSTANT_DESC (TYPEDEF_OR_REF_DESC + 5)
99 #define HAS_CATTR_DESC (HAS_CONSTANT_DESC + 5)
107 MONO_TABLE_INTERFACEIMPL,
108 MONO_TABLE_MEMBERREF,
110 MONO_TABLE_DECLSECURITY,
113 MONO_TABLE_STANDALONESIG,
114 MONO_TABLE_MODULEREF,
117 MONO_TABLE_ASSEMBLYREF,
119 MONO_TABLE_EXPORTEDTYPE,
120 MONO_TABLE_MANIFESTRESOURCE,
121 MONO_TABLE_GENERICPARAM,
123 #define HAS_FIELD_MARSHAL_DESC (HAS_CATTR_DESC + 22)
129 #define HAS_DECL_SECURITY_DESC (HAS_FIELD_MARSHAL_DESC + 4)
136 #define MEMBERREF_PARENT_DESC (HAS_DECL_SECURITY_DESC + 5)
145 #define HAS_SEMANTICS_DESC (MEMBERREF_PARENT_DESC + 7)
151 #define METHODDEF_OR_REF_DESC (HAS_SEMANTICS_DESC + 4)
155 MONO_TABLE_MEMBERREF,
157 #define MEMBER_FORWARDED_DESC (METHODDEF_OR_REF_DESC + 4)
163 #define IMPLEMENTATION_DESC (MEMBER_FORWARDED_DESC + 4)
167 MONO_TABLE_ASSEMBLYREF,
168 MONO_TABLE_EXPORTEDTYPE,
170 #define CATTR_TYPE_DESC (IMPLEMENTATION_DESC + 5)
176 MONO_TABLE_MEMBERREF,
179 #define RES_SCOPE_DESC (CATTR_TYPE_DESC + 7)
183 MONO_TABLE_MODULEREF,
184 MONO_TABLE_ASSEMBLYREF,
187 #define TYPE_OR_METHODDEF_DESC (RES_SCOPE_DESC + 6)
197 guint32 translated_offset;
209 guint32 rellocationsRVA;
210 guint16 numberOfRelocations;
225 gboolean report_error;
226 gboolean report_warning;
229 DataDirectory data_directories [16];
230 guint32 section_count;
231 SectionHeader *sections;
233 OffsetAndSize metadata_streams [5]; //offset from begin of the image
236 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception) \
238 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
239 vinfo->info.status = __status; \
240 vinfo->info.message = ( __msg); \
241 vinfo->exception_type = (__exception); \
242 (__ctx)->errors = g_slist_prepend ((__ctx)->errors, vinfo); \
245 #define ADD_WARNING(__ctx, __msg) \
247 if ((__ctx)->report_warning) { \
248 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_WARNING, MONO_EXCEPTION_INVALID_PROGRAM); \
249 (__ctx)->valid = 0; \
254 #define ADD_ERROR_NO_RETURN(__ctx, __msg) \
256 if ((__ctx)->report_error) \
257 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
258 (__ctx)->valid = 0; \
261 #define ADD_ERROR(__ctx, __msg) \
263 if ((__ctx)->report_error) \
264 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
265 (__ctx)->valid = 0; \
269 #define FAIL(__ctx, __msg) \
271 if ((__ctx)->report_error) \
272 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
273 (__ctx)->valid = 0; \
277 #define CHECK_STATE() do { if (!ctx.valid) goto cleanup; } while (0)
279 #define CHECK_ERROR() do { if (!ctx->valid) return; } while (0)
281 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
282 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
284 #if SIZEOF_VOID_P == 4
285 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
287 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
290 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
291 #define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
294 dword_align (const char *ptr)
296 #if SIZEOF_VOID_P == 8
297 return (const char *) (((guint64) (ptr + 3)) & ~3);
299 return (const char *) (((guint32) (ptr + 3)) & ~3);
304 add_from_mono_error (VerifyContext *ctx, MonoError *error)
306 if (mono_error_ok (error))
309 ADD_ERROR (ctx, g_strdup (mono_error_get_message (error)));
310 mono_error_cleanup (error);
314 pe_signature_offset (VerifyContext *ctx)
316 return read32 (ctx->data + 0x3c);
320 pe_header_offset (VerifyContext *ctx)
322 return read32 (ctx->data + 0x3c) + 4;
326 bounds_check_virtual_address (VerifyContext *ctx, guint32 rva, guint32 size)
330 if (rva + size < rva) //overflow
333 if (ctx->stage > STAGE_PE) {
334 MonoCLIImageInfo *iinfo = ctx->image->image_info;
335 const int top = iinfo->cli_section_count;
336 MonoSectionTable *tables = iinfo->cli_section_tables;
339 for (i = 0; i < top; i++) {
340 guint32 base = tables->st_virtual_address;
341 guint32 end = base + tables->st_raw_data_size;
343 if (rva >= base && rva + size <= end)
346 /*if ((addr >= tables->st_virtual_address) &&
347 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
349 return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
359 for (i = 0; i < ctx->section_count; ++i) {
360 guint32 base = ctx->sections [i].baseRVA;
361 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
362 if (rva >= base && rva + size <= end)
369 bounds_check_datadir (DataDirectory *dir, guint32 offset, guint32 size)
371 if (dir->translated_offset > offset)
373 if (dir->size < size)
375 return offset + size <= dir->translated_offset + dir->size;
379 bounds_check_offset (OffsetAndSize *off, guint32 offset, guint32 size)
381 if (off->offset > offset)
384 if (off->size < size)
387 return offset + size <= off->offset + off->size;
391 translate_rva (VerifyContext *ctx, guint32 rva)
395 if (ctx->stage > STAGE_PE)
396 return mono_cli_rva_image_map (ctx->image, rva);
401 for (i = 0; i < ctx->section_count; ++i) {
402 guint32 base = ctx->sections [i].baseRVA;
403 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
404 if (rva >= base && rva <= end) {
405 guint32 res = (rva - base) + ctx->sections [i].baseOffset;
407 return res >= ctx->size ? INVALID_OFFSET : res;
411 return INVALID_OFFSET;
415 verify_msdos_header (VerifyContext *ctx)
419 ADD_ERROR (ctx, g_strdup ("Not enough space for the MS-DOS header"));
420 if (ctx->data [0] != 0x4d || ctx->data [1] != 0x5a)
421 ADD_ERROR (ctx, g_strdup ("Invalid MS-DOS watermark"));
422 lfanew = pe_signature_offset (ctx);
423 if (lfanew > ctx->size - 4)
424 ADD_ERROR (ctx, g_strdup ("MS-DOS lfanew offset points to outside of the file"));
428 verify_pe_header (VerifyContext *ctx)
430 guint32 offset = pe_signature_offset (ctx);
431 const char *pe_header = ctx->data + offset;
432 if (pe_header [0] != 'P' || pe_header [1] != 'E' ||pe_header [2] != 0 ||pe_header [3] != 0)
433 ADD_ERROR (ctx, g_strdup ("Invalid PE header watermark"));
437 if (offset > ctx->size - 20)
438 ADD_ERROR (ctx, g_strdup ("File with truncated pe header"));
439 if (read16 (pe_header) != 0x14c)
440 ADD_ERROR (ctx, g_strdup ("Invalid PE header Machine value"));
444 verify_pe_optional_header (VerifyContext *ctx)
446 guint32 offset = pe_header_offset (ctx);
447 guint32 header_size, file_alignment;
448 const char *pe_header = ctx->data + offset;
449 const char *pe_optional_header = pe_header + 20;
451 header_size = read16 (pe_header + 16);
454 if (header_size < 2) /*must be at least 2 or we won't be able to read magic*/
455 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
457 if (offset > ctx->size - header_size || header_size > ctx->size)
458 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
460 if (read16 (pe_optional_header) == 0x10b) {
461 if (header_size != 224)
462 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header size %d", header_size));
464 /* LAMESPEC MS plays around this value and ignore it during validation
465 if (read32 (pe_optional_header + 28) != 0x400000)
466 ADD_ERROR (ctx, g_strdup_printf ("Invalid Image base %x", read32 (pe_optional_header + 28)));*/
467 if (read32 (pe_optional_header + 32) != 0x2000)
468 ADD_ERROR (ctx, g_strdup_printf ("Invalid Section Aligmnent %x", read32 (pe_optional_header + 32)));
469 file_alignment = read32 (pe_optional_header + 36);
470 if (file_alignment != 0x200 && file_alignment != 0x1000)
471 ADD_ERROR (ctx, g_strdup_printf ("Invalid file Aligmnent %x", file_alignment));
472 /* All the junk in the middle is irrelevant, specially for mono. */
473 if (read32 (pe_optional_header + 92) > 0x10)
474 ADD_ERROR (ctx, g_strdup_printf ("Too many data directories %x", read32 (pe_optional_header + 92)));
476 if (read16 (pe_optional_header) == 0x20B)
477 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle PE32+"));
479 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header magic %d", read16 (pe_optional_header)));
484 load_section_table (VerifyContext *ctx)
487 SectionHeader *sections;
488 guint32 offset = pe_header_offset (ctx);
489 const char *ptr = ctx->data + offset;
490 guint16 num_sections = ctx->section_count = read16 (ptr + 2);
492 offset += 244;/*FIXME, this constant is different under PE32+*/
495 if (num_sections * 40 > ctx->size - offset)
496 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
498 sections = ctx->sections = g_new0 (SectionHeader, num_sections);
499 for (i = 0; i < num_sections; ++i) {
500 sections [i].size = read32 (ptr + 8);
501 sections [i].baseRVA = read32 (ptr + 12);
502 sections [i].baseOffset = read32 (ptr + 20);
503 sections [i].rellocationsRVA = read32 (ptr + 24);
504 sections [i].numberOfRelocations = read16 (ptr + 32);
508 ptr = ctx->data + offset; /*reset it to the beggining*/
509 for (i = 0; i < num_sections; ++i) {
510 guint32 raw_size, flags;
511 if (sections [i].baseOffset == 0)
512 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with intialized data only"));
513 if (sections [i].baseOffset >= ctx->size)
514 ADD_ERROR (ctx, g_strdup_printf ("Invalid PointerToRawData %x points beyond EOF", sections [i].baseOffset));
515 if (sections [i].size > ctx->size - sections [i].baseOffset)
516 ADD_ERROR (ctx, g_strdup ("Invalid VirtualSize points beyond EOF"));
518 raw_size = read32 (ptr + 16);
519 if (raw_size < sections [i].size)
520 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with SizeOfRawData < VirtualSize"));
522 if (raw_size > ctx->size - sections [i].baseOffset)
523 ADD_ERROR (ctx, g_strdup_printf ("Invalid SizeOfRawData %x points beyond EOF", raw_size));
525 if (sections [i].rellocationsRVA || sections [i].numberOfRelocations)
526 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't handle section relocation"));
528 flags = read32 (ptr + 36);
529 /*TODO 0xFE0000E0 is all flags from cil-coff.h OR'd. Make it a less magical number*/
530 if (flags == 0 || (flags & ~0xFE0000E0) != 0)
531 ADD_ERROR (ctx, g_strdup_printf ("Invalid section flags %x", flags));
538 is_valid_data_directory (int i)
540 /*LAMESPEC 4 == certificate 6 == debug, MS uses both*/
541 return i == 1 || i == 2 || i == 5 || i == 12 || i == 14 || i == 4 || i == 6;
545 load_data_directories (VerifyContext *ctx)
547 guint32 offset = pe_header_offset (ctx) + 116; /*FIXME, this constant is different under PE32+*/
548 const char *ptr = ctx->data + offset;
551 for (i = 0; i < 16; ++i) {
552 guint32 rva = read32 (ptr);
553 guint32 size = read32 (ptr + 4);
555 /*LAMESPEC the authenticode data directory format is different. We don't support CAS, so lets ignore for now.*/
556 if (i == CERTIFICATE_TABLE_IDX) {
560 if ((rva != 0 || size != 0) && !is_valid_data_directory (i))
561 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d", i));
563 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
564 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d rva/size pair %x/%x", i, rva, size));
566 ctx->data_directories [i].rva = rva;
567 ctx->data_directories [i].size = size;
568 ctx->data_directories [i].translated_offset = translate_rva (ctx, rva);
574 #define SIZE_OF_MSCOREE (sizeof ("mscoree.dll"))
576 #define SIZE_OF_CORMAIN (sizeof ("_CorExeMain"))
579 verify_hint_name_table (VerifyContext *ctx, guint32 import_rva, const char *table_name)
582 guint32 hint_table_rva;
584 import_rva = translate_rva (ctx, import_rva);
585 g_assert (import_rva != INVALID_OFFSET);
587 hint_table_rva = read32 (ctx->data + import_rva);
588 if (!bounds_check_virtual_address (ctx, hint_table_rva, SIZE_OF_CORMAIN + 2))
589 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint/Name rva %d for %s", hint_table_rva, table_name));
591 hint_table_rva = translate_rva (ctx, hint_table_rva);
592 g_assert (hint_table_rva != INVALID_OFFSET);
593 ptr = ctx->data + hint_table_rva + 2;
595 if (memcmp ("_CorExeMain", ptr, SIZE_OF_CORMAIN) && memcmp ("_CorDllMain", ptr, SIZE_OF_CORMAIN)) {
596 char name[SIZE_OF_CORMAIN];
597 memcpy (name, ptr, SIZE_OF_CORMAIN);
598 name [SIZE_OF_CORMAIN - 1] = 0;
599 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint / Name: '%s'", name));
604 verify_import_table (VerifyContext *ctx)
606 DataDirectory it = ctx->data_directories [IMPORT_TABLE_IDX];
607 guint32 offset = it.translated_offset;
608 const char *ptr = ctx->data + offset;
609 guint32 name_rva, ilt_rva, iat_rva;
611 g_assert (offset != INVALID_OFFSET);
614 ADD_ERROR (ctx, g_strdup_printf ("Import table size %d is smaller than 40", it.size));
616 ilt_rva = read32 (ptr);
617 if (ilt_rva && !bounds_check_virtual_address (ctx, ilt_rva, 8))
618 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Lookup Table rva %x", ilt_rva));
620 name_rva = read32 (ptr + 12);
621 if (name_rva && !bounds_check_virtual_address (ctx, name_rva, SIZE_OF_MSCOREE))
622 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name rva %x", name_rva));
624 iat_rva = read32 (ptr + 16);
626 if (!bounds_check_virtual_address (ctx, iat_rva, 8))
627 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Address Table rva %x", iat_rva));
629 if (iat_rva != ctx->data_directories [IAT_IDX].rva)
630 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));
634 name_rva = translate_rva (ctx, name_rva);
635 g_assert (name_rva != INVALID_OFFSET);
636 ptr = ctx->data + name_rva;
638 if (memcmp ("mscoree.dll", ptr, SIZE_OF_MSCOREE)) {
639 char name[SIZE_OF_MSCOREE];
640 memcpy (name, ptr, SIZE_OF_MSCOREE);
641 name [SIZE_OF_MSCOREE - 1] = 0;
642 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name: '%s'", name));
647 verify_hint_name_table (ctx, ilt_rva, "Import Lookup Table");
652 verify_hint_name_table (ctx, iat_rva, "Import Address Table");
656 verify_resources_table (VerifyContext *ctx)
658 DataDirectory it = ctx->data_directories [RESOURCE_TABLE_IDX];
660 guint16 named_entries, id_entries;
661 const char *ptr, *root, *end;
667 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));
669 offset = it.translated_offset;
670 root = ptr = ctx->data + offset;
671 end = root + it.size;
673 g_assert (offset != INVALID_OFFSET);
675 named_entries = read16 (ptr + 12);
676 id_entries = read16 (ptr + 14);
678 if ((named_entries + id_entries) * 8 + 16 > it.size)
679 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));
681 /* XXX at least one unmanaged resource is added due to a call to AssemblyBuilder::DefineVersionInfoResource ()
682 if (named_entries || id_entries)
683 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support full verification of PECOFF resources"));
687 /*----------nothing from here on can use data_directory---*/
690 get_data_dir (VerifyContext *ctx, int idx)
692 MonoCLIImageInfo *iinfo = ctx->image->image_info;
693 MonoPEDirEntry *entry= &iinfo->cli_header.datadir.pe_export_table;
697 res.rva = entry->rva;
698 res.size = entry->size;
699 res.translated_offset = translate_rva (ctx, res.rva);
704 verify_cli_header (VerifyContext *ctx)
706 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
712 ADD_ERROR (ctx, g_strdup_printf ("CLI header missing"));
715 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size in data directory %d must be 72", it.size));
717 offset = it.translated_offset;
718 ptr = ctx->data + offset;
720 g_assert (offset != INVALID_OFFSET);
722 if (read16 (ptr) != 72)
723 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size %d must be 72", read16 (ptr)));
725 if (!bounds_check_virtual_address (ctx, read32 (ptr + 8), read32 (ptr + 12)))
726 ADD_ERROR (ctx, g_strdup_printf ("Invalid medatata section rva/size pair %x/%x", read32 (ptr + 8), read32 (ptr + 12)));
729 if (!read32 (ptr + 8) || !read32 (ptr + 12))
730 ADD_ERROR (ctx, g_strdup_printf ("Missing medatata section in the CLI header"));
732 if ((read32 (ptr + 16) & ~0x0001000B) != 0)
733 ADD_ERROR (ctx, g_strdup_printf ("Invalid CLI header flags"));
736 for (i = 0; i < 6; ++i) {
737 guint32 rva = read32 (ptr);
738 guint32 size = read32 (ptr + 4);
740 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
741 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli section %i rva/size pair %x/%x", i, rva, size));
746 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't support cli header section %d", i));
751 pad4 (guint32 offset)
753 if (offset & 0x3) //pad to the next 4 byte boundary
754 offset = (offset & ~0x3) + 4;
759 verify_metadata_header (VerifyContext *ctx)
762 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
763 guint32 offset, section_count;
766 offset = it.translated_offset;
767 ptr = ctx->data + offset;
768 g_assert (offset != INVALID_OFFSET);
770 //build a directory entry for the metadata root
772 it.rva = read32 (ptr);
774 it.size = read32 (ptr);
775 it.translated_offset = offset = translate_rva (ctx, it.rva);
777 ptr = ctx->data + offset;
778 g_assert (offset != INVALID_OFFSET);
781 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small %d (at least 20 bytes required for initial decoding)", it.size));
783 if (read32 (ptr) != 0x424A5342)
784 ADD_ERROR (ctx, g_strdup_printf ("Invalid metadata signature, expected 0x424A5342 but got %08x", read32 (ptr)));
786 offset = pad4 (offset + 16 + read32 (ptr + 12));
788 if (!bounds_check_datadir (&it, offset, 4))
789 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));
791 ptr = ctx->data + offset; //move to streams header
793 section_count = read16 (ptr + 2);
794 if (section_count < 2)
795 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section must have at least 2 streams (#~ and #GUID)"));
800 for (i = 0; i < section_count; ++i) {
801 guint32 stream_off, stream_size;
802 int string_size, stream_idx;
804 if (!bounds_check_datadir (&it, offset, 8))
805 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));
807 stream_off = it.translated_offset + read32 (ptr);
808 stream_size = read32 (ptr + 4);
810 if (!bounds_check_datadir (&it, stream_off, stream_size))
811 ADD_ERROR (ctx, g_strdup_printf ("Invalid stream header %d offset/size pair %x/%x", 0, stream_off, stream_size));
816 for (string_size = 0; string_size < 32; ++string_size) {
817 if (!bounds_check_datadir (&it, offset++, 1))
818 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small to decode stream header %d name", i));
819 if (!ptr [string_size])
823 if (ptr [string_size])
824 ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d name larger than 32 bytes", i));
826 if (!strncmp ("#Strings", ptr, 9))
827 stream_idx = STRINGS_STREAM;
828 else if (!strncmp ("#US", ptr, 4))
829 stream_idx = USER_STRINGS_STREAM;
830 else if (!strncmp ("#Blob", ptr, 6))
831 stream_idx = BLOB_STREAM;
832 else if (!strncmp ("#GUID", ptr, 6))
833 stream_idx = GUID_STREAM;
834 else if (!strncmp ("#~", ptr, 3))
835 stream_idx = TILDE_STREAM;
837 ADD_WARNING (ctx, g_strdup_printf ("Metadata stream header %d invalid name %s", i, ptr));
838 offset = pad4 (offset);
839 ptr = ctx->data + offset;
843 if (ctx->metadata_streams [stream_idx].offset != 0)
844 ADD_ERROR (ctx, g_strdup_printf ("Duplicated metadata stream header %s", ptr));
846 ctx->metadata_streams [stream_idx].offset = stream_off;
847 ctx->metadata_streams [stream_idx].size = stream_size;
849 offset = pad4 (offset);
850 ptr = ctx->data + offset;
853 if (!ctx->metadata_streams [TILDE_STREAM].size)
854 ADD_ERROR (ctx, g_strdup_printf ("Metadata #~ stream missing"));
855 if (!ctx->metadata_streams [GUID_STREAM].size)
856 ADD_ERROR (ctx, g_strdup_printf ("Metadata guid stream missing"));
860 verify_tables_schema (VerifyContext *ctx)
862 OffsetAndSize tables_area = ctx->metadata_streams [TILDE_STREAM];
863 unsigned offset = tables_area.offset;
864 const char *ptr = ctx->data + offset;
865 guint64 valid_tables;
869 if (tables_area.size < 24)
870 ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for initial decoding (requires 24 bytes)", tables_area.size));
872 if (ptr [4] != 2 && ptr [4] != 1)
873 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata major version %d, expected 2", ptr [4]));
875 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata minor version %d, expected 0", ptr [5]));
877 if ((ptr [6] & ~0x7) != 0)
878 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]));
880 valid_tables = read64 (ptr + 8);
882 for (i = 0; i < 64; ++i) {
883 if (!(valid_tables & ((guint64)1 << i)))
886 /*MS Extensions: 0x3 0x5 0x7 0x13 0x16
887 Unused: 0x1E 0x1F 0x2D-0x3F
888 We don't care about the MS extensions.*/
889 if (i == 0x3 || i == 0x5 || i == 0x7 || i == 0x13 || i == 0x16)
890 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support MS specific table %x", i));
891 if (i == 0x1E || i == 0x1F || i >= 0x2D)
892 ADD_ERROR (ctx, g_strdup_printf ("Invalid table %x", i));
896 if (tables_area.size < 24 + count * 4)
897 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));
900 for (i = 0; i < 64; ++i) {
901 if (valid_tables & ((guint64)1 << i)) {
902 guint32 row_count = read32 (ptr);
903 if (row_count > (1 << 24) - 1)
904 ADD_ERROR (ctx, g_strdup_printf ("Invalid Table %d row count: %d. Mono only supports 16777215 rows", i, row_count));
910 /*----------nothing from here on can use data_directory or metadata_streams ---*/
913 get_col_offset (VerifyContext *ctx, int table, int column)
915 guint32 bitfield = ctx->image->tables [table].size_bitfield;
919 offset += mono_metadata_table_size (bitfield, column);
925 get_col_size (VerifyContext *ctx, int table, int column)
927 return mono_metadata_table_size (ctx->image->tables [table].size_bitfield, column);
931 get_metadata_stream (VerifyContext *ctx, MonoStreamHeader *header)
934 res.offset = header->data - ctx->data;
935 res.size = header->size;
941 is_valid_string_full_with_image (MonoImage *image, guint32 offset, gboolean allow_empty)
943 guint32 heap_offset = (char*)image->heap_strings.data - image->raw_data;
944 guint32 heap_size = image->heap_strings.size;
947 const char *data = image->raw_data + heap_offset;
949 if (offset >= heap_size)
951 if (CHECK_ADDP_OVERFLOW_UN (data, offset))
954 if (!mono_utf8_validate_and_len_with_bounds (data + offset, heap_size - offset, &length, NULL))
956 return allow_empty || length > 0;
961 is_valid_string_full (VerifyContext *ctx, guint32 offset, gboolean allow_empty)
963 return is_valid_string_full_with_image (ctx->image, offset, allow_empty);
967 is_valid_string (VerifyContext *ctx, guint32 offset)
969 return is_valid_string_full (ctx, offset, TRUE);
973 is_valid_non_empty_string (VerifyContext *ctx, guint32 offset)
975 return is_valid_string_full (ctx, offset, FALSE);
979 is_valid_guid (VerifyContext *ctx, guint32 offset)
981 OffsetAndSize guids = get_metadata_stream (ctx, &ctx->image->heap_guid);
982 return guids.size >= 8 && guids.size - 8 >= offset;
986 get_coded_index_token (int token_kind, guint32 coded_token)
988 guint32 bits = coded_index_desc [token_kind];
989 return coded_token >> bits;
993 get_coded_index_table (int kind, guint32 coded_token)
995 guint32 idx, bits = coded_index_desc [kind];
997 idx = coded_token & ((1 << bits) - 1);
998 return coded_index_desc [kind + idx];
1002 make_coded_token (int kind, guint32 table, guint32 table_idx)
1004 guint32 bits = coded_index_desc [kind++];
1005 guint32 tables = coded_index_desc [kind++];
1007 for (i = 0; i < tables; ++i) {
1008 if (coded_index_desc [kind++] == table)
1009 return ((table_idx + 1) << bits) | i;
1011 g_assert_not_reached ();
1016 is_valid_coded_index_with_image (MonoImage *image, int token_kind, guint32 coded_token)
1018 guint32 bits = coded_index_desc [token_kind++];
1019 guint32 table_count = coded_index_desc [token_kind++];
1020 guint32 table = coded_token & ((1 << bits) - 1);
1021 guint32 token = coded_token >> bits;
1023 if (table >= table_count)
1026 /*token_kind points to the first table idx*/
1027 table = coded_index_desc [token_kind + table];
1029 if (table == INVALID_TABLE)
1031 return token <= image->tables [table].rows;
1035 is_valid_coded_index (VerifyContext *ctx, int token_kind, guint32 coded_token)
1037 return is_valid_coded_index_with_image (ctx->image, token_kind, coded_token);
1044 MonoTableInfo *table;
1048 token_locator (const void *a, const void *b)
1050 RowLocator *loc = (RowLocator *)a;
1051 unsigned const char *row = (unsigned const char *)b;
1052 guint32 token = loc->col_size == 2 ? read16 (row + loc->col_offset) : read32 (row + loc->col_offset);
1054 VERIFIER_DEBUG ( printf ("\tfound token %x at idx %d\n", token, ((const char*)row - loc->table->base) / loc->table->row_size) );
1055 return (int)loc->token - (int)token;
1059 search_sorted_table (VerifyContext *ctx, int table, int column, guint32 coded_token)
1061 MonoTableInfo *tinfo = &ctx->image->tables [table];
1063 const char *res, *base;
1064 locator.token = coded_token;
1065 locator.col_offset = get_col_offset (ctx, table, column);
1066 locator.col_size = get_col_size (ctx, table, column);
1067 locator.table = tinfo;
1071 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) );
1072 res = bsearch (&locator, base, tinfo->rows, tinfo->row_size, token_locator);
1076 return (res - base) / tinfo->row_size;
1079 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1081 get_string_ptr (VerifyContext *ctx, guint offset)
1083 return ctx->image->heap_strings.data + offset;
1086 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1088 string_cmp (VerifyContext *ctx, const char *str, guint offset)
1091 return strcmp (str, "");
1093 return strcmp (str, get_string_ptr (ctx, offset));
1097 mono_verifier_is_corlib (MonoImage *image)
1099 gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ?
1100 TRUE : mono_security_core_clr_is_platform_image (image);
1102 return trusted_location && image->module_name && !strcmp ("mscorlib.dll", image->module_name);
1106 typedef_is_system_object (VerifyContext *ctx, guint32 *data)
1108 return mono_verifier_is_corlib (ctx->image) && !string_cmp (ctx, "System", data [MONO_TYPEDEF_NAMESPACE]) && !string_cmp (ctx, "Object", data [MONO_TYPEDEF_NAME]);
1112 decode_value (const char *_ptr, unsigned available, unsigned *value, unsigned *size)
1115 const unsigned char *ptr = (const unsigned char *)_ptr;
1123 if ((b & 0x80) == 0) {
1126 } else if ((b & 0x40) == 0) {
1130 *value = ((b & 0x3f) << 8 | ptr [1]);
1135 *value = ((b & 0x1f) << 24) |
1145 decode_signature_header (VerifyContext *ctx, guint32 offset, guint32 *size, const char **first_byte)
1147 MonoStreamHeader blob = ctx->image->heap_blob;
1148 guint32 value, enc_size;
1150 if (offset >= blob.size)
1153 if (!decode_value (blob.data + offset, blob.size - offset, &value, &enc_size))
1156 if (CHECK_ADD4_OVERFLOW_UN (offset, enc_size))
1161 if (ADD_IS_GREATER_OR_OVF (offset, value, blob.size))
1165 *first_byte = blob.data + offset;
1170 safe_read (const char **_ptr, const char *limit, unsigned *dest, int size)
1172 const char *ptr = *_ptr;
1173 if (ptr + size > limit)
1177 *dest = *((guint8*)ptr);
1181 *dest = read16 (ptr);
1185 *dest = read32 (ptr);
1194 safe_read_compressed_int (const char **_ptr, const char *limit, unsigned *dest)
1197 const char *ptr = *_ptr;
1198 gboolean res = decode_value (ptr, limit - ptr, dest, &size);
1203 #define safe_read8(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 1)
1204 #define safe_read_cint(VAR, PTR, LIMIT) safe_read_compressed_int (&PTR, LIMIT, &VAR)
1205 #define safe_read16(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 2)
1206 #define safe_read32(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 4)
1209 parse_type (VerifyContext *ctx, const char **_ptr, const char *end);
1212 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged);
1215 parse_custom_mods (VerifyContext *ctx, const char **_ptr, const char *end)
1217 const char *ptr = *_ptr;
1222 if (!safe_read8 (type, ptr, end))
1223 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the type"));
1225 if (type != MONO_TYPE_CMOD_REQD && type != MONO_TYPE_CMOD_OPT) {
1230 if (!safe_read_cint (token, ptr, end))
1231 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the token"));
1233 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1234 FAIL (ctx, g_strdup_printf ("CustomMod: invalid TypeDefOrRef token %x", token));
1242 parse_array_shape (VerifyContext *ctx, const char **_ptr, const char *end)
1244 const char *ptr = *_ptr;
1246 unsigned size, num, i;
1248 if (!safe_read8 (val, ptr, end))
1249 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for Rank"));
1252 FAIL (ctx, g_strdup ("ArrayShape: Invalid shape with zero Rank"));
1254 if (!safe_read_cint (size, ptr, end))
1255 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumSizes"));
1257 for (i = 0; i < size; ++i) {
1258 if (!safe_read_cint (num, ptr, end))
1259 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for Size of rank %d", i + 1));
1262 if (!safe_read_cint (size, ptr, end))
1263 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumLoBounds"));
1265 for (i = 0; i < size; ++i) {
1266 if (!safe_read_cint (num, ptr, end))
1267 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for LoBound of rank %d", i + 1));
1275 parse_generic_inst (VerifyContext *ctx, const char **_ptr, const char *end)
1277 const char *ptr = *_ptr;
1279 unsigned count, token, i;
1281 if (!safe_read8 (type, ptr, end))
1282 FAIL (ctx, g_strdup ("GenericInst: Not enough room for kind"));
1284 if (type != MONO_TYPE_CLASS && type != MONO_TYPE_VALUETYPE)
1285 FAIL (ctx, g_strdup_printf ("GenericInst: Invalid GenericInst kind %x\n", type));
1287 if (!safe_read_cint (token, ptr, end))
1288 FAIL (ctx, g_strdup ("GenericInst: Not enough room for type token"));
1290 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1291 FAIL (ctx, g_strdup_printf ("GenericInst: invalid TypeDefOrRef token %x", token));
1294 if (mono_metadata_token_index (ctx->token) == get_coded_index_token (TYPEDEF_OR_REF_DESC, token) &&
1295 mono_metadata_token_table (ctx->token) == get_coded_index_table (TYPEDEF_OR_REF_DESC, token))
1296 FAIL (ctx, g_strdup_printf ("Type: Recurside generic instance specification (%x). A type signature can't reference itself", ctx->token));
1299 if (!safe_read_cint (count, ptr, end))
1300 FAIL (ctx, g_strdup ("GenericInst: Not enough room for argument count"));
1303 FAIL (ctx, g_strdup ("GenericInst: Zero arguments generic instance"));
1305 for (i = 0; i < count; ++i) {
1306 if (!parse_type (ctx, &ptr, end))
1307 FAIL (ctx, g_strdup_printf ("GenericInst: invalid generic argument %d", i + 1));
1314 parse_type (VerifyContext *ctx, const char **_ptr, const char *end)
1316 const char *ptr = *_ptr;
1320 if (!safe_read8 (type, ptr, end))
1321 FAIL (ctx, g_strdup ("Type: Not enough room for the type"));
1323 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_PTR) ||
1324 (type >= MONO_TYPE_VALUETYPE && type <= MONO_TYPE_GENERICINST) ||
1325 (type >= MONO_TYPE_I && type <= MONO_TYPE_U) ||
1326 (type >= MONO_TYPE_FNPTR && type <= MONO_TYPE_MVAR)))
1327 FAIL (ctx, g_strdup_printf ("Type: Invalid type kind %x\n", type));
1331 if (!parse_custom_mods (ctx, &ptr, end))
1332 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1334 if (!safe_read8 (type, ptr, end))
1335 FAIL (ctx, g_strdup ("Type: Not enough room to parse the pointer type"));
1337 if (type != MONO_TYPE_VOID) {
1339 if (!parse_type (ctx, &ptr, end))
1340 FAIL (ctx, g_strdup ("Type: Could not parse pointer type"));
1344 case MONO_TYPE_VALUETYPE:
1345 case MONO_TYPE_CLASS:
1346 if (!safe_read_cint (token, ptr, end))
1347 FAIL (ctx, g_strdup ("Type: Not enough room for the type token"));
1349 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1350 FAIL (ctx, g_strdup_printf ("Type: invalid TypeDefOrRef token %x", token));
1352 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, token))
1353 FAIL (ctx, g_strdup_printf ("Type: zero TypeDefOrRef token %x", token));
1355 if (mono_metadata_token_index (ctx->token) == get_coded_index_token (TYPEDEF_OR_REF_DESC, token) &&
1356 mono_metadata_token_table (ctx->token) == get_coded_index_table (TYPEDEF_OR_REF_DESC, token))
1357 FAIL (ctx, g_strdup_printf ("Type: Recursive type specification (%x). A type signature can't reference itself", ctx->token));
1362 case MONO_TYPE_MVAR:
1363 if (!safe_read_cint (token, ptr, end))
1364 FAIL (ctx, g_strdup ("Type: Not enough room for to decode generic argument number"));
1367 case MONO_TYPE_ARRAY:
1368 if (!parse_type (ctx, &ptr, end))
1369 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1370 if (!parse_array_shape (ctx, &ptr, end))
1371 FAIL (ctx, g_strdup ("Type: Could not parse array shape"));
1374 case MONO_TYPE_GENERICINST:
1375 if (!parse_generic_inst (ctx, &ptr, end))
1376 FAIL (ctx, g_strdup ("Type: Could not parse generic inst"));
1379 case MONO_TYPE_FNPTR:
1380 if (!parse_method_signature (ctx, &ptr, end, TRUE, TRUE))
1381 FAIL (ctx, g_strdup ("Type: Could not parse method pointer signature"));
1384 case MONO_TYPE_SZARRAY:
1385 if (!parse_custom_mods (ctx, &ptr, end))
1386 FAIL (ctx, g_strdup ("Type: Failed to parse array element custom attr"));
1387 if (!parse_type (ctx, &ptr, end))
1388 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1396 parse_return_type (VerifyContext *ctx, const char **_ptr, const char *end)
1401 if (!parse_custom_mods (ctx, _ptr, end))
1405 if (!safe_read8 (type, ptr, end))
1406 FAIL (ctx, g_strdup ("ReturnType: Not enough room for the type"));
1408 if (type == MONO_TYPE_VOID || type == MONO_TYPE_TYPEDBYREF) {
1413 //it's a byref, update the cursor ptr
1414 if (type == MONO_TYPE_BYREF)
1417 return parse_type (ctx, _ptr, end);
1421 parse_param (VerifyContext *ctx, const char **_ptr, const char *end)
1426 if (!parse_custom_mods (ctx, _ptr, end))
1430 if (!safe_read8 (type, ptr, end))
1431 FAIL (ctx, g_strdup ("Param: Not enough room for the type"));
1433 if (type == MONO_TYPE_TYPEDBYREF) {
1438 //it's a byref, update the cursor ptr
1439 if (type == MONO_TYPE_BYREF)
1442 return parse_type (ctx, _ptr, end);
1446 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged)
1449 unsigned param_count = 0, gparam_count = 0, type = 0, i;
1450 const char *ptr = *_ptr;
1451 gboolean saw_sentinel = FALSE;
1453 if (!safe_read8 (cconv, ptr, end))
1454 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the call conv"));
1457 FAIL (ctx, g_strdup ("MethodSig: CallConv has 0x80 set"));
1459 if (allow_unmanaged) {
1460 if ((cconv & 0x0F) > MONO_CALL_VARARG)
1461 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not valid, it's %x", cconv & 0x0F));
1462 } else if ((cconv & 0x0F) != MONO_CALL_DEFAULT && (cconv & 0x0F) != MONO_CALL_VARARG)
1463 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not Default or Vararg, it's %x", cconv & 0x0F));
1465 if ((cconv & 0x10) && !safe_read_cint (gparam_count, ptr, end))
1466 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the generic param count"));
1468 if ((cconv & 0x10) && gparam_count == 0)
1469 FAIL (ctx, g_strdup ("MethodSig: Signature with generics but zero arity"));
1471 if (allow_unmanaged && (cconv & 0x10))
1472 FAIL (ctx, g_strdup ("MethodSig: Standalone signature with generic params"));
1474 if (!safe_read_cint (param_count, ptr, end))
1475 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the param count"));
1477 if (!parse_return_type (ctx, &ptr, end))
1478 FAIL (ctx, g_strdup ("MethodSig: Error parsing return type"));
1480 for (i = 0; i < param_count; ++i) {
1481 if (allow_sentinel) {
1482 if (!safe_read8 (type, ptr, end))
1483 FAIL (ctx, g_strdup_printf ("MethodSig: Not enough room for param %d type", i));
1485 if (type == MONO_TYPE_SENTINEL) {
1486 if ((cconv & 0x0F) != MONO_CALL_VARARG)
1487 FAIL (ctx, g_strdup ("MethodSig: Found sentinel but signature is not vararg"));
1490 FAIL (ctx, g_strdup ("MethodSig: More than one sentinel type"));
1492 saw_sentinel = TRUE;
1498 if (!parse_param (ctx, &ptr, end))
1499 FAIL (ctx, g_strdup_printf ("MethodSig: Error parsing arg %d", i));
1507 parse_property_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1510 unsigned param_count = 0, i;
1511 const char *ptr = *_ptr;
1513 if (!safe_read8 (sig, ptr, end))
1514 FAIL (ctx, g_strdup ("PropertySig: Not enough room for signature"));
1516 if (sig != 0x08 && sig != 0x28)
1517 FAIL (ctx, g_strdup_printf ("PropertySig: Signature is not 0x28 or 0x08: %x", sig));
1519 if (!safe_read_cint (param_count, ptr, end))
1520 FAIL (ctx, g_strdup ("PropertySig: Not enough room for the param count"));
1522 if (!parse_custom_mods (ctx, &ptr, end))
1525 if (!parse_type (ctx, &ptr, end))
1526 FAIL (ctx, g_strdup ("PropertySig: Could not parse property type"));
1528 for (i = 0; i < param_count; ++i) {
1529 if (!parse_type (ctx, &ptr, end))
1530 FAIL (ctx, g_strdup_printf ("PropertySig: Error parsing arg %d", i));
1538 parse_field (VerifyContext *ctx, const char **_ptr, const char *end)
1540 const char *ptr = *_ptr;
1541 unsigned signature = 0;
1543 if (!safe_read8 (signature, ptr, end))
1544 FAIL (ctx, g_strdup ("Field: Not enough room for field signature"));
1546 if (signature != 0x06)
1547 FAIL (ctx, g_strdup_printf ("Field: Invalid signature 0x%x, must be 6", signature));
1549 if (!parse_custom_mods (ctx, &ptr, end))
1552 if (safe_read8 (signature, ptr, end)) {
1553 if (signature != MONO_TYPE_BYREF)
1558 return parse_type (ctx, _ptr, end);
1562 parse_locals_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1565 unsigned locals_count = 0, i;
1566 const char *ptr = *_ptr;
1568 if (!safe_read8 (sig, ptr, end))
1569 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for signature"));
1572 FAIL (ctx, g_strdup_printf ("LocalsSig: Signature is not 0x28 or 0x08: %x", sig));
1574 if (!safe_read_cint (locals_count, ptr, end))
1575 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for the param count"));
1577 /* LAMEIMPL: MS sometimes generates empty local signatures and its verifier is ok with.
1578 if (locals_count == 0)
1579 FAIL (ctx, g_strdup ("LocalsSig: Signature with zero locals"));
1582 for (i = 0; i < locals_count; ++i) {
1583 if (!safe_read8 (sig, ptr, end))
1584 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1586 while (sig == MONO_TYPE_CMOD_REQD || sig == MONO_TYPE_CMOD_OPT || sig == MONO_TYPE_PINNED) {
1587 if (sig != MONO_TYPE_PINNED && !parse_custom_mods (ctx, &ptr, end))
1588 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1589 if (!safe_read8 (sig, ptr, end))
1590 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1593 if (sig == MONO_TYPE_BYREF) {
1594 if (!safe_read8 (sig, ptr, end))
1595 FAIL (ctx, g_strdup_printf ("Type: Not enough room for byref type for local %d", i));
1596 if (sig == MONO_TYPE_TYPEDBYREF)
1597 FAIL (ctx, g_strdup_printf ("Type: Invalid type typedref& for local %d", i));
1600 if (sig == MONO_TYPE_TYPEDBYREF)
1605 if (!parse_type (ctx, &ptr, end))
1606 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1614 is_valid_field_signature (VerifyContext *ctx, guint32 offset)
1617 unsigned signature = 0;
1618 const char *ptr = NULL, *end;
1620 if (!decode_signature_header (ctx, offset, &size, &ptr))
1621 FAIL (ctx, g_strdup ("FieldSig: Could not decode signature header"));
1624 if (!safe_read8 (signature, ptr, end))
1625 FAIL (ctx, g_strdup ("FieldSig: Not enough room for the signature"));
1628 FAIL (ctx, g_strdup_printf ("FieldSig: Invalid signature %x", signature));
1631 return parse_field (ctx, &ptr, end);
1635 is_valid_method_signature (VerifyContext *ctx, guint32 offset)
1638 const char *ptr = NULL, *end;
1640 if (!decode_signature_header (ctx, offset, &size, &ptr))
1641 FAIL (ctx, g_strdup ("MethodSig: Could not decode signature header"));
1644 return parse_method_signature (ctx, &ptr, end, FALSE, FALSE);
1648 is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
1651 unsigned signature = 0;
1652 const char *ptr = NULL, *end;
1654 if (!decode_signature_header (ctx, offset, &size, &ptr))
1655 FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
1658 if (!safe_read8 (signature, ptr, end))
1659 FAIL (ctx, g_strdup ("MemberRefSig: Not enough room for the call conv"));
1662 if (signature == 0x06)
1663 return parse_field (ctx, &ptr, end);
1665 return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1669 is_valid_cattr_blob (VerifyContext *ctx, guint32 offset)
1672 unsigned prolog = 0;
1673 const char *ptr = NULL, *end;
1678 if (!decode_signature_header (ctx, offset, &size, &ptr))
1679 FAIL (ctx, g_strdup ("CustomAttribute: Could not decode signature header"));
1682 if (!safe_read16 (prolog, ptr, end))
1683 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1686 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1692 is_valid_cattr_type (MonoType *type)
1696 if (type->type == MONO_TYPE_OBJECT || (type->type >= MONO_TYPE_BOOLEAN && type->type <= MONO_TYPE_STRING))
1699 if (type->type == MONO_TYPE_VALUETYPE) {
1700 klass = mono_class_from_mono_type (type);
1701 return klass && klass->enumtype;
1704 if (type->type == MONO_TYPE_CLASS)
1705 return mono_class_from_mono_type (type) == mono_defaults.systemtype_class;
1711 is_valid_ser_string_full (VerifyContext *ctx, const char **str_start, guint32 *str_len, const char **_ptr, const char *end)
1714 const char *ptr = *_ptr;
1720 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string size"));
1723 if (*ptr == (char)0xFF) {
1728 if (!safe_read_cint (size, ptr, end))
1729 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string size"));
1731 if (ADDP_IS_GREATER_OR_OVF (ptr, size, end))
1732 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string"));
1742 is_valid_ser_string (VerifyContext *ctx, const char **_ptr, const char *end)
1744 const char *dummy_str;
1746 return is_valid_ser_string_full (ctx, &dummy_str, &dummy_int, _ptr, end);
1750 get_enum_by_encoded_name (VerifyContext *ctx, const char **_ptr, const char *end)
1754 const char *str_start = NULL;
1755 const char *ptr = *_ptr;
1757 guint32 str_len = 0;
1759 if (!is_valid_ser_string_full (ctx, &str_start, &str_len, &ptr, end))
1762 /*NULL or empty string*/
1763 if (str_start == NULL || str_len == 0) {
1764 ADD_ERROR_NO_RETURN (ctx, g_strdup ("CustomAttribute: Null or empty enum name"));
1768 enum_name = g_memdup (str_start, str_len + 1);
1769 enum_name [str_len] = 0;
1770 type = mono_reflection_type_from_name (enum_name, ctx->image);
1772 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute: Invalid enum class %s", enum_name));
1778 klass = mono_class_from_mono_type (type);
1779 if (!klass || !klass->enumtype) {
1780 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute:Class %s::%s is not an enum", klass->name_space, klass->name));
1789 is_valid_fixed_param (VerifyContext *ctx, MonoType *mono_type, const char **_ptr, const char *end)
1792 const char *ptr = *_ptr;
1794 guint32 element_count, i;
1797 klass = mono_type->data.klass;
1798 type = mono_type->type;
1802 case MONO_TYPE_BOOLEAN:
1809 case MONO_TYPE_CHAR:
1823 case MONO_TYPE_STRING:
1825 return is_valid_ser_string (ctx, _ptr, end);
1827 case MONO_TYPE_OBJECT: {
1828 unsigned sub_type = 0;
1829 if (!safe_read8 (sub_type, ptr, end))
1830 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array type"));
1832 if (sub_type >= MONO_TYPE_BOOLEAN && sub_type <= MONO_TYPE_STRING) {
1836 if (sub_type == MONO_TYPE_ENUM) {
1837 klass = get_enum_by_encoded_name (ctx, &ptr, end);
1841 klass = klass->element_class;
1842 type = klass->byval_arg.type;
1845 if (sub_type == 0x50) { /*Type*/
1847 return is_valid_ser_string (ctx, _ptr, end);
1849 if (sub_type == MONO_TYPE_SZARRAY) {
1850 MonoType simple_type = {{0}};
1852 if (!safe_read8 (etype, ptr, end))
1853 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array element type"));
1855 if (etype == MONO_TYPE_ENUM) {
1856 klass = get_enum_by_encoded_name (ctx, &ptr, end);
1859 } else if ((etype >= MONO_TYPE_BOOLEAN && etype <= MONO_TYPE_STRING) || etype == 0x51) {
1860 simple_type.type = etype == 0x51 ? MONO_TYPE_OBJECT : etype;
1861 klass = mono_class_from_mono_type (&simple_type);
1863 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype));
1865 type = MONO_TYPE_SZARRAY;
1868 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid boxed object type %x", sub_type));
1872 case MONO_TYPE_CLASS:
1873 if (klass != mono_defaults.systemtype_class)
1874 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid class parameter type %s:%s ",klass->name_space, klass->name));
1876 return is_valid_ser_string (ctx, _ptr, end);
1878 case MONO_TYPE_VALUETYPE:
1879 if (!klass || !klass->enumtype)
1880 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid valuetype parameter expected enum %s:%s ",klass->name_space, klass->name));
1882 klass = klass->element_class;
1883 type = klass->byval_arg.type;
1886 case MONO_TYPE_SZARRAY:
1887 mono_type = &klass->byval_arg;
1888 if (!is_valid_cattr_type (mono_type))
1889 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %s:%s ",klass->name_space, klass->name));
1890 if (!safe_read32 (element_count, ptr, end))
1891 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid class parameter type %s:%s ",klass->name_space, klass->name));
1892 if (element_count == 0xFFFFFFFFu) {
1896 for (i = 0; i < element_count; ++i) {
1897 if (!is_valid_fixed_param (ctx, mono_type, &ptr, end))
1903 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid parameter type %x ", type));
1906 if (ADDP_IS_GREATER_OR_OVF (ptr, elem_size, end))
1907 FAIL (ctx, g_strdup ("CustomAttribute: Not enough space for element"));
1908 *_ptr = ptr + elem_size;
1913 is_valid_cattr_content (VerifyContext *ctx, MonoMethod *ctor, const char *ptr, guint32 size)
1916 unsigned prolog = 0;
1918 MonoMethodSignature *sig;
1923 FAIL (ctx, g_strdup ("CustomAttribute: Invalid constructor"));
1925 sig = mono_method_signature_checked (ctor, &error);
1926 if (!mono_error_ok (&error)) {
1927 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute: Invalid constructor signature %s", mono_error_get_message (&error)));
1928 mono_error_cleanup (&error);
1932 if (sig->sentinelpos != -1 || sig->call_convention == MONO_CALL_VARARG)
1933 FAIL (ctx, g_strdup ("CustomAttribute: Constructor cannot have VARAG signature"));
1937 if (!safe_read16 (prolog, ptr, end))
1938 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1941 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1943 args = sig->param_count;
1944 for (i = 0; i < args; ++i) {
1945 MonoType *arg_type = sig->params [i];
1946 if (!is_valid_fixed_param (ctx, arg_type, &ptr, end))
1950 if (!safe_read16 (num_named, ptr, end))
1951 FAIL (ctx, g_strdup ("CustomAttribute: Not enough space for num_named field"));
1953 for (i = 0; i < num_named; ++i) {
1954 MonoType *type, simple_type = {{0}};
1957 if (!safe_read8 (kind, ptr, end))
1958 FAIL (ctx, g_strdup_printf ("CustomAttribute: Not enough space for named parameter %d kind", i));
1959 if (kind != 0x53 && kind != 0x54)
1960 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid named parameter %d kind %x", i, kind));
1961 if (!safe_read8 (kind, ptr, end))
1962 FAIL (ctx, g_strdup_printf ("CustomAttribute: Not enough space for named parameter %d type", i));
1964 if (kind >= MONO_TYPE_BOOLEAN && kind <= MONO_TYPE_STRING) {
1965 simple_type.type = kind;
1966 type = &simple_type;
1967 } else if (kind == MONO_TYPE_ENUM) {
1968 MonoClass *klass = get_enum_by_encoded_name (ctx, &ptr, end);
1971 type = &klass->byval_arg;
1972 } else if (kind == 0x50) {
1973 type = &mono_defaults.systemtype_class->byval_arg;
1974 } else if (kind == 0x51) {
1975 type = &mono_defaults.object_class->byval_arg;
1976 } else if (kind == MONO_TYPE_SZARRAY) {
1979 if (!safe_read8 (etype, ptr, end))
1980 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array element type"));
1982 if (etype == MONO_TYPE_ENUM) {
1983 klass = get_enum_by_encoded_name (ctx, &ptr, end);
1986 } else if ((etype >= MONO_TYPE_BOOLEAN && etype <= MONO_TYPE_STRING) || etype == 0x51) {
1987 simple_type.type = etype == 0x51 ? MONO_TYPE_OBJECT : etype;
1988 klass = mono_class_from_mono_type (&simple_type);
1990 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype));
1992 type = &mono_array_class_get (klass, 1)->byval_arg;
1994 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid named parameter type %x", kind));
1997 if (!is_valid_ser_string (ctx, &ptr, end))
2000 if (!is_valid_fixed_param (ctx, type, &ptr, end))
2009 is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
2011 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2012 //TODO do proper verification
2013 return blob.size >= 1 && blob.size - 1 >= offset;
2017 is_valid_permission_set (VerifyContext *ctx, guint32 offset)
2019 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2020 //TODO do proper verification
2021 return blob.size >= 1 && blob.size - 1 >= offset;
2025 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
2028 unsigned signature = 0;
2029 const char *ptr = NULL, *end;
2031 if (!decode_signature_header (ctx, offset, &size, &ptr))
2032 FAIL (ctx, g_strdup ("StandAloneSig: Could not decode signature header"));
2035 if (!safe_read8 (signature, ptr, end))
2036 FAIL (ctx, g_strdup ("StandAloneSig: Not enough room for the call conv"));
2039 if (signature == 0x07)
2040 return parse_locals_signature (ctx, &ptr, end);
2042 /*F# and managed C++ produce standalonesig for fields even thou the spec doesn't mention it.*/
2043 if (signature == 0x06)
2044 return parse_field (ctx, &ptr, end);
2046 return parse_method_signature (ctx, &ptr, end, TRUE, TRUE);
2050 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
2053 const char *ptr = NULL, *end;
2055 if (!decode_signature_header (ctx, offset, &size, &ptr))
2056 FAIL (ctx, g_strdup ("PropertySig: Could not decode signature header"));
2059 return parse_property_signature (ctx, &ptr, end);
2063 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
2066 const char *ptr = NULL, *end;
2069 if (!decode_signature_header (ctx, offset, &size, &ptr))
2070 FAIL (ctx, g_strdup ("TypeSpec: Could not decode signature header"));
2073 if (!parse_custom_mods (ctx, &ptr, end))
2076 if (!safe_read8 (type, ptr, end))
2077 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for type"));
2079 if (type == MONO_TYPE_BYREF) {
2080 if (!safe_read8 (type, ptr, end))
2081 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for byref type"));
2082 if (type == MONO_TYPE_TYPEDBYREF)
2083 FAIL (ctx, g_strdup ("TypeSpec: Invalid type typedref&"));
2086 if (type == MONO_TYPE_TYPEDBYREF)
2090 return parse_type (ctx, &ptr, end);
2094 is_valid_methodspec_blob (VerifyContext *ctx, guint32 offset)
2097 const char *ptr = NULL, *end;
2099 unsigned count = 0, i;
2101 if (!decode_signature_header (ctx, offset, &size, &ptr))
2102 FAIL (ctx, g_strdup ("MethodSpec: Could not decode signature header"));
2105 if (!safe_read8 (type, ptr, end))
2106 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for call convention"));
2109 FAIL (ctx, g_strdup_printf ("MethodSpec: Invalid call convention 0x%x, expected 0x0A", type));
2111 if (!safe_read_cint (count, ptr, end))
2112 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for parameter count"));
2115 FAIL (ctx, g_strdup ("MethodSpec: Zero generic argument count"));
2117 for (i = 0; i < count; ++i) {
2118 if (!parse_type (ctx, &ptr, end))
2119 FAIL (ctx, g_strdup_printf ("MethodSpec: Could not parse parameter %d", i + 1));
2125 is_valid_blob_object (VerifyContext *ctx, guint32 offset, guint32 minsize)
2127 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2128 guint32 entry_size, bytes;
2130 if (blob.size < offset)
2133 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
2136 if (entry_size < minsize)
2139 if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
2141 entry_size += bytes;
2143 return !ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size);
2147 is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
2149 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2150 guint32 size, entry_size, bytes;
2152 if (blob.size < offset)
2153 FAIL (ctx, g_strdup ("ContantValue: invalid offset"));
2155 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
2156 FAIL (ctx, g_strdup ("ContantValue: not enough space to decode size"));
2158 if (type == MONO_TYPE_STRING) {
2159 //String is encoded as: compressed_int:len len *bytes
2162 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size))
2163 FAIL (ctx, g_strdup_printf ("ContantValue: not enough space for string, required %d but got %d", entry_size * 2, blob.size - offset));
2169 case MONO_TYPE_BOOLEAN:
2174 case MONO_TYPE_CHAR:
2182 case MONO_TYPE_CLASS:
2192 g_assert_not_reached ();
2195 if (size != entry_size)
2196 FAIL (ctx, g_strdup_printf ("ContantValue: Expected size %d but got %d", size, entry_size));
2200 if (ADD_IS_GREATER_OR_OVF (offset, size, blob.size))
2201 FAIL (ctx, g_strdup_printf ("ContantValue: Not enough room for constant, required %d but have %d", size, blob.size - offset));
2203 if (type == MONO_TYPE_CLASS && read32 (ctx->data + blob.offset + offset))
2204 FAIL (ctx, g_strdup_printf ("ContantValue: Type is class but value is not null"));
2208 #define FAT_HEADER_INVALID_FLAGS ~(0x3 | 0x8 | 0x10 | 0xF000)
2209 //only 0x01, 0x40 and 0x80 are allowed
2210 #define SECTION_HEADER_INVALID_FLAGS 0x3E
2213 is_valid_method_header (VerifyContext *ctx, guint32 rva, guint32 *locals_token)
2215 unsigned local_vars_tok, code_size, offset = mono_cli_rva_image_map (ctx->image, rva);
2216 unsigned header = 0;
2217 unsigned fat_header = 0, size = 0, max_stack;
2218 const char *ptr = NULL, *end;
2222 if (offset == INVALID_ADDRESS)
2223 FAIL (ctx, g_strdup ("MethodHeader: Invalid RVA"));
2225 ptr = ctx->data + offset;
2226 end = ctx->data + ctx->size; /*no worries if it spawns multiple sections*/
2228 if (!safe_read8 (header, ptr, end))
2229 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for header"));
2231 switch (header & 0x3) {
2234 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid header type 0x%x", header & 0x3));
2237 if (ADDP_IS_GREATER_OR_OVF (ptr, header, end))
2238 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for method body. Required %d, but only %d is available", header, (int)(end - ptr)));
2243 if (!safe_read16 (fat_header, ptr, end))
2244 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for fat header"));
2246 size = (fat_header >> 12) & 0xF;
2248 FAIL (ctx, g_strdup ("MethodHeader: header size must be 3"));
2250 if (!safe_read16 (max_stack, ptr, end))
2251 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for max stack"));
2253 if (!safe_read32 (code_size, ptr, end))
2254 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for code size"));
2256 if (!safe_read32 (local_vars_tok, ptr, end))
2257 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for local vars tok"));
2259 if (local_vars_tok) {
2260 if (((local_vars_tok >> 24) & 0xFF) != 0x11)
2261 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature table 0x%x", ((local_vars_tok >> 24) & 0xFF)));
2262 if ((local_vars_tok & 0xFFFFFF) > ctx->image->tables [MONO_TABLE_STANDALONESIG].rows)
2263 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature points to invalid row 0x%x", local_vars_tok & 0xFFFFFF));
2264 if (!(local_vars_tok & 0xFFFFFF))
2265 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature with zero index"));
2266 *locals_token = local_vars_tok & 0xFFFFFF;
2269 if (fat_header & FAT_HEADER_INVALID_FLAGS)
2270 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid fat signature flags %x", fat_header & FAT_HEADER_INVALID_FLAGS));
2272 if (ADDP_IS_GREATER_OR_OVF (ptr, code_size, end))
2273 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for code %d", code_size));
2275 if (!(fat_header & 0x08))
2281 unsigned section_header = 0, section_size = 0;
2284 ptr = dword_align (ptr);
2285 if (!safe_read32 (section_header, ptr, end))
2286 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for data section header"));
2288 if (section_header & SECTION_HEADER_INVALID_FLAGS)
2289 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section header flags 0x%x", section_header & SECTION_HEADER_INVALID_FLAGS));
2291 is_fat = (section_header & METHOD_HEADER_SECTION_FAT_FORMAT) != 0;
2292 section_size = (section_header >> 8) & (is_fat ? 0xFFFFFF : 0xFF);
2294 if (section_size < 4)
2295 FAIL (ctx, g_strdup_printf ("MethodHeader: Section size too small"));
2297 if (ADDP_IS_GREATER_OR_OVF (ptr, section_size - 4, end)) /*must be section_size -4 as ptr was incremented by safe_read32*/
2298 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section content %d", section_size));
2300 if (section_header & METHOD_HEADER_SECTION_EHTABLE) {
2301 guint32 i, clauses = section_size / (is_fat ? 24 : 12);
2303 LAMEIMPL: MS emits section_size without accounting for header size.
2304 Mono does as the spec says. section_size is header + section
2305 MS's peverify happily accepts both.
2307 if ((clauses * (is_fat ? 24 : 12) != section_size) && (clauses * (is_fat ? 24 : 12) + 4 != section_size))
2308 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid EH section size %d, it's not of the expected size %d", section_size, clauses * (is_fat ? 24 : 12)));
2310 /* only verify the class token is verified as the rest is done by the IL verifier*/
2311 for (i = 0; i < clauses; ++i) {
2312 unsigned flags = *(unsigned char*)ptr;
2313 unsigned class_token = 0;
2314 ptr += (is_fat ? 20 : 8);
2315 if (!safe_read32 (class_token, ptr, end))
2316 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section %d", i));
2317 if (flags == MONO_EXCEPTION_CLAUSE_NONE && class_token) {
2318 guint table = mono_metadata_token_table (class_token);
2319 if (table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPESPEC)
2320 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token table %x", i, table));
2321 if (mono_metadata_token_index (class_token) > ctx->image->tables [table].rows)
2322 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token index %x", i, mono_metadata_token_index (class_token)));
2327 if (!(section_header & METHOD_HEADER_SECTION_MORE_SECTS))
2334 verify_module_table (VerifyContext *ctx)
2336 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
2337 guint32 data [MONO_MODULE_SIZE];
2339 if (table->rows != 1)
2340 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
2342 mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
2344 if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
2345 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
2347 if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
2348 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
2350 if (data [MONO_MODULE_ENC] != 0)
2351 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
2353 if (data [MONO_MODULE_ENCBASE] != 0)
2354 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
2358 verify_typeref_table (VerifyContext *ctx)
2360 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
2364 for (i = 0; i < table->rows; ++i) {
2365 mono_verifier_verify_typeref_row (ctx->image, i, &error);
2366 add_from_mono_error (ctx, &error);
2370 /*bits 9,11,14,15,19,21,24-31 */
2371 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 14) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
2373 verify_typedef_table (VerifyContext *ctx)
2375 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2376 guint32 data [MONO_TYPEDEF_SIZE];
2377 guint32 fieldlist = 1, methodlist = 1, visibility;
2380 if (table->rows == 0)
2381 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2383 for (i = 0; i < table->rows; ++i) {
2384 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2385 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
2386 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
2388 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
2389 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
2391 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
2392 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2394 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
2395 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2397 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) && (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
2398 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
2400 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
2401 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
2403 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
2404 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
2406 if (data [MONO_TYPEDEF_EXTENDS] && !is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
2407 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
2409 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
2410 if ((visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) &&
2411 search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1) == -1)
2412 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d has nested visibility but no rows in the NestedClass table", i));
2414 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
2415 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
2417 if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2418 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
2420 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
2421 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));
2423 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
2424 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
2426 if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
2427 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
2429 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
2430 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));
2432 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
2433 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
2438 verify_typedef_table_full (VerifyContext *ctx)
2440 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2441 guint32 data [MONO_TYPEDEF_SIZE];
2444 if (table->rows == 0)
2445 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2447 for (i = 0; i < table->rows; ++i) {
2448 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2451 /*XXX it's ok if <module> extends object, or anything at all, actually. */
2452 /*if (data [MONO_TYPEDEF_EXTENDS] != 0)
2453 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
2458 if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
2459 if (data [MONO_TYPEDEF_EXTENDS])
2460 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
2462 gboolean is_sys_obj = typedef_is_system_object (ctx, data);
2463 gboolean has_parent = get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]) != 0;
2467 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
2470 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
2478 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
2480 verify_field_table (VerifyContext *ctx)
2482 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2483 guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
2486 module_field_list = (guint32)-1;
2487 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2488 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2489 module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
2492 for (i = 0; i < table->rows; ++i) {
2493 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2494 flags = data [MONO_FIELD_FLAGS];
2496 if (flags & INVALID_FIELD_FLAG_BITS)
2497 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
2499 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)
2500 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
2502 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
2503 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
2505 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
2506 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
2508 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
2509 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
2511 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
2512 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
2513 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
2515 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
2516 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2517 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2519 if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
2520 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2521 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
2523 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
2524 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
2525 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2527 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
2528 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
2530 if (data [MONO_FIELD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_FIELD_SIGNATURE], 1))
2531 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature blob token 0x%x", i, data [MONO_FIELD_SIGNATURE]));
2533 //TODO verify contant flag
2535 if (i + 1 < module_field_list) {
2536 guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
2537 if (!(flags & FIELD_ATTRIBUTE_STATIC))
2538 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
2539 if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
2540 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
2546 verify_field_table_full (VerifyContext *ctx)
2548 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2549 guint32 data [MONO_FIELD_SIZE];
2552 for (i = 0; i < table->rows; ++i) {
2553 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2555 if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
2556 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
2560 /*bits 8,9,10,11,13,14,15*/
2561 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
2563 verify_method_table (VerifyContext *ctx)
2565 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2566 guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
2567 guint32 paramlist = 1;
2568 gboolean is_ctor, is_cctor;
2572 module_method_list = (guint32)-1;
2573 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2574 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2575 module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
2578 for (i = 0; i < table->rows; ++i) {
2579 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2580 rva = data [MONO_METHOD_RVA];
2581 implflags = data [MONO_METHOD_IMPLFLAGS];
2582 flags = data [MONO_METHOD_FLAGS];
2583 access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
2584 code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
2587 if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
2588 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
2591 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
2593 if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
2594 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
2596 name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
2597 is_ctor = !strcmp (".ctor", name);
2598 is_cctor = !strcmp (".cctor", name);
2600 if ((is_ctor || is_cctor) &&
2601 search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
2602 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
2604 if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
2605 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
2607 if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
2608 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
2609 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
2610 if (flags & METHOD_ATTRIBUTE_FINAL)
2611 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and Final", i));
2612 if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
2613 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
2616 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
2617 ADD_WARNING (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
2619 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
2620 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
2622 //XXX no checks against cas stuff 10,11,12,13)
2624 //TODO check iface with .ctor (15,16)
2626 if (i + 1 < module_method_list) {
2627 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2628 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
2629 if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
2630 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
2631 if (!(access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED || access == METHOD_ATTRIBUTE_PUBLIC || access == METHOD_ATTRIBUTE_PRIVATE))
2632 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public or Private", i));
2635 //TODO check valuetype for synchronized
2637 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
2638 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
2640 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
2641 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
2642 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
2643 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2644 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but not Static", i));
2647 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
2648 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2649 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
2651 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
2652 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
2654 //TODO check signature contents
2657 if (flags & METHOD_ATTRIBUTE_ABSTRACT)
2658 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", i));
2659 if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
2660 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
2662 if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2663 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
2666 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2668 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
2669 if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
2670 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
2672 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
2673 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
2675 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
2676 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
2678 if (data [MONO_METHOD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHOD_SIGNATURE], 1))
2679 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature blob token 0x%x", i, data [MONO_METHOD_SIGNATURE]));
2681 if (data [MONO_METHOD_PARAMLIST] == 0)
2682 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
2684 if (data [MONO_METHOD_PARAMLIST] < paramlist)
2685 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));
2687 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
2688 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
2690 paramlist = data [MONO_METHOD_PARAMLIST];
2696 verify_method_table_full (VerifyContext *ctx)
2698 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2699 guint32 data [MONO_METHOD_SIZE], rva, locals_token;
2702 for (i = 0; i < table->rows; ++i) {
2703 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2704 rva = data [MONO_METHOD_RVA];
2706 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
2707 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
2709 if (rva && !is_valid_method_header (ctx, rva, &locals_token))
2710 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
2715 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
2717 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2718 guint32 row = *current_method;
2719 guint32 paramlist, tmp;
2722 paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
2723 while (row < table->rows) {
2724 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
2725 if (tmp > paramlist) {
2726 *current_method = row;
2727 return tmp - paramlist;
2732 /*no more methods, all params apply to the last one*/
2733 *current_method = table->rows;
2738 #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))
2740 verify_param_table (VerifyContext *ctx)
2742 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
2743 guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
2744 gboolean first_param = TRUE;
2747 if (ctx->image->tables [MONO_TABLE_METHOD].rows == 0) {
2748 if (table->rows > 0)
2749 ADD_ERROR (ctx, g_strdup ("Param table has rows while the method table has zero"));
2753 remaining_params = get_next_param_count (ctx, ¤t_method);
2755 for (i = 0; i < table->rows; ++i) {
2756 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
2757 flags = data [MONO_PARAM_FLAGS];
2759 if (flags & INVALID_PARAM_FLAGS_BITS)
2760 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
2762 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
2763 if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
2764 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
2766 if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
2767 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
2770 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)
2771 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
2773 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
2774 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
2776 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
2777 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
2779 first_param = FALSE;
2780 sequence = data [MONO_PARAM_SEQUENCE];
2781 if (--remaining_params == 0) {
2782 remaining_params = get_next_param_count (ctx, ¤t_method);
2789 verify_interfaceimpl_table (VerifyContext *ctx)
2791 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
2792 guint32 data [MONO_INTERFACEIMPL_SIZE];
2795 for (i = 0; i < table->rows; ++i) {
2796 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
2797 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2798 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2800 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2801 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
2803 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2804 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
2809 verify_memberref_table (VerifyContext *ctx)
2811 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2812 guint32 data [MONO_MEMBERREF_SIZE];
2815 for (i = 0; i < table->rows; ++i) {
2816 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2818 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2819 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
2821 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2822 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
2824 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
2825 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
2827 if (data [MONO_MEMBERREF_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_MEMBERREF_SIGNATURE], 1))
2828 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d invalid signature blob token 0x%x", i, data [MONO_MEMBERREF_SIGNATURE]));
2834 verify_memberref_table_full (VerifyContext *ctx)
2836 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2837 guint32 data [MONO_MEMBERREF_SIZE];
2840 for (i = 0; i < table->rows; ++i) {
2841 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2843 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
2844 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field 0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
2849 verify_constant_table (VerifyContext *ctx)
2851 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
2852 guint32 data [MONO_CONSTANT_SIZE], type;
2855 for (i = 0; i < table->rows; ++i) {
2856 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
2857 type = data [MONO_CONSTANT_TYPE];
2859 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
2860 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
2862 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2863 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
2865 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2866 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
2868 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
2869 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
2874 verify_cattr_table (VerifyContext *ctx)
2876 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2877 guint32 data [MONO_CUSTOM_ATTR_SIZE];
2880 for (i = 0; i < table->rows; ++i) {
2881 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2883 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
2884 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2886 if (!is_valid_coded_index (ctx, CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]) || !get_coded_index_token (CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]))
2887 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Type field 0x%08x", i, data [MONO_CUSTOM_ATTR_TYPE]));
2889 if (data [MONO_CUSTOM_ATTR_VALUE] && !is_valid_blob_object (ctx, data [MONO_CUSTOM_ATTR_VALUE], 0))
2890 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d invalid value blob 0x%x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2895 verify_cattr_table_full (VerifyContext *ctx)
2897 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2900 guint32 data [MONO_CUSTOM_ATTR_SIZE], mtoken, size;
2903 for (i = 0; i < table->rows; ++i) {
2904 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2906 if (!is_valid_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
2907 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2909 mtoken = data [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
2910 switch (data [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
2911 case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
2912 mtoken |= MONO_TOKEN_METHOD_DEF;
2914 case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
2915 mtoken |= MONO_TOKEN_MEMBER_REF;
2918 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute constructor row %d Token 0x%08x", i, data [MONO_CUSTOM_ATTR_TYPE]));
2921 ctor = mono_get_method (ctx->image, mtoken, NULL);
2923 /*This can't fail since this is checked in is_valid_cattr_blob*/
2924 g_assert (decode_signature_header (ctx, data [MONO_CUSTOM_ATTR_VALUE], &size, &ptr));
2926 if (!is_valid_cattr_content (ctx, ctor, ptr, size))
2927 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute content row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2932 verify_field_marshal_table (VerifyContext *ctx)
2934 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2935 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2938 for (i = 0; i < table->rows; ++i) {
2939 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2941 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2942 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
2944 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2945 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
2947 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
2948 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
2950 if (!is_valid_blob_object (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE], 1))
2951 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d invalid NativeType blob 0x%x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2956 verify_field_marshal_table_full (VerifyContext *ctx)
2958 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2959 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2962 for (i = 0; i < table->rows; ++i) {
2963 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2965 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
2966 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2971 verify_decl_security_table (VerifyContext *ctx)
2973 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2974 guint32 data [MONO_DECL_SECURITY_SIZE];
2977 for (i = 0; i < table->rows; ++i) {
2978 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2980 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2981 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
2983 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2984 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
2986 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
2987 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
2992 verify_decl_security_table_full (VerifyContext *ctx)
2994 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2995 guint32 data [MONO_DECL_SECURITY_SIZE];
2998 for (i = 0; i < table->rows; ++i) {
2999 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
3001 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
3002 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
3007 verify_class_layout_table (VerifyContext *ctx)
3009 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
3010 guint32 data [MONO_CLASS_LAYOUT_SIZE];
3013 for (i = 0; i < table->rows; ++i) {
3014 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
3016 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3017 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
3019 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
3031 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
3037 verify_field_layout_table (VerifyContext *ctx)
3039 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
3040 guint32 data [MONO_FIELD_LAYOUT_SIZE];
3043 for (i = 0; i < table->rows; ++i) {
3044 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
3046 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
3047 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
3052 verify_standalonesig_table (VerifyContext *ctx)
3054 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
3055 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
3058 for (i = 0; i < table->rows; ++i) {
3059 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
3061 if (data [MONO_STAND_ALONE_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_STAND_ALONE_SIGNATURE], 1))
3062 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d invalid signature 0x%x", i, data [MONO_STAND_ALONE_SIGNATURE]));
3067 verify_standalonesig_table_full (VerifyContext *ctx)
3069 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
3070 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
3073 for (i = 0; i < table->rows; ++i) {
3074 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
3076 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
3077 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
3082 verify_eventmap_table (VerifyContext *ctx)
3084 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
3085 guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
3088 for (i = 0; i < table->rows; ++i) {
3089 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
3091 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3092 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
3094 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
3095 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
3097 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
3101 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
3103 verify_event_table (VerifyContext *ctx)
3105 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
3106 guint32 data [MONO_EVENT_SIZE];
3109 for (i = 0; i < table->rows; ++i) {
3110 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
3112 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
3113 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
3115 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
3116 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
3118 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
3119 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
3124 verify_event_table_full (VerifyContext *ctx)
3126 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
3127 MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
3128 guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
3129 gboolean found_add, found_remove;
3132 for (i = 0; i < table->rows; ++i) {
3133 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
3135 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
3136 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
3138 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
3140 //first we move to the first row for this event
3142 if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
3146 //now move forward looking for AddOn and RemoveOn rows
3147 found_add = found_remove = FALSE;
3148 while (idx < sema_table->rows) {
3149 mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
3150 if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
3152 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
3154 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
3155 found_remove = TRUE;
3156 if (found_add && found_remove)
3162 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
3164 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
3169 verify_propertymap_table (VerifyContext *ctx)
3171 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
3172 guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
3175 for (i = 0; i < table->rows; ++i) {
3176 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
3178 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3179 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
3181 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
3182 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
3184 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
3188 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
3190 verify_property_table (VerifyContext *ctx)
3192 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
3193 guint32 data [MONO_PROPERTY_SIZE];
3196 for (i = 0; i < table->rows; ++i) {
3197 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
3199 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
3200 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
3202 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
3203 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
3205 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
3206 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
3208 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
3209 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
3210 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
3216 verify_methodimpl_table (VerifyContext *ctx)
3218 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
3219 guint32 data [MONO_METHODIMPL_SIZE];
3222 for (i = 0; i < table->rows; ++i) {
3223 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
3225 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3226 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
3228 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
3229 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
3231 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
3232 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
3234 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
3235 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
3237 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
3238 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
3243 verify_moduleref_table (VerifyContext *ctx)
3245 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
3246 guint32 data [MONO_MODULEREF_SIZE];
3249 for (i = 0; i < table->rows; ++i) {
3250 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
3252 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
3253 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
3258 verify_typespec_table (VerifyContext *ctx)
3260 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
3261 guint32 data [MONO_TYPESPEC_SIZE];
3264 for (i = 0; i < table->rows; ++i) {
3265 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
3267 if (data [MONO_TYPESPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_TYPESPEC_SIGNATURE], 1))
3268 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
3273 verify_typespec_table_full (VerifyContext *ctx)
3275 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
3276 guint32 data [MONO_TYPESPEC_SIZE];
3279 for (i = 0; i < table->rows; ++i) {
3280 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
3281 ctx->token = (i + 1) | MONO_TOKEN_TYPE_SPEC;
3282 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
3283 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
3288 #define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 12) | (1 << 13))
3290 verify_implmap_table (VerifyContext *ctx)
3292 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
3293 guint32 data [MONO_IMPLMAP_SIZE], cconv;
3296 for (i = 0; i < table->rows; ++i) {
3297 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
3299 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
3300 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
3302 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
3303 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
3304 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
3306 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
3307 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
3309 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
3310 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
3312 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
3313 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
3315 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
3316 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
3318 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULEREF].rows)
3319 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
3324 verify_fieldrva_table (VerifyContext *ctx)
3326 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
3327 guint32 data [MONO_FIELD_RVA_SIZE];
3330 for (i = 0; i < table->rows; ++i) {
3331 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
3333 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
3334 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
3336 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
3337 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
3341 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 4) | (1 << 8) | (1 << 14) | (1 << 15))
3343 verify_assembly_table (VerifyContext *ctx)
3345 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
3346 guint32 data [MONO_ASSEMBLY_SIZE], hash;
3349 if (table->rows > 1)
3350 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
3352 for (i = 0; i < table->rows; ++i) {
3353 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
3355 hash = data [MONO_ASSEMBLY_HASH_ALG];
3356 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
3357 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
3359 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
3360 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
3362 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY], 1))
3363 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
3365 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
3366 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
3368 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
3369 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
3373 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~(1)
3375 verify_assemblyref_table (VerifyContext *ctx)
3377 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
3378 guint32 data [MONO_ASSEMBLYREF_SIZE];
3381 for (i = 0; i < table->rows; ++i) {
3382 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
3384 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
3385 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
3387 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY], 1))
3388 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
3390 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
3391 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
3393 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
3394 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
3396 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE], 1))
3397 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
3401 #define INVALID_FILE_FLAGS_BITS ~(1)
3403 verify_file_table (VerifyContext *ctx)
3405 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
3406 guint32 data [MONO_FILE_SIZE];
3409 for (i = 0; i < table->rows; ++i) {
3410 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
3412 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
3413 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
3415 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
3416 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
3418 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE], 1))
3419 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
3423 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
3425 verify_exportedtype_table (VerifyContext *ctx)
3427 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
3428 guint32 data [MONO_EXP_TYPE_SIZE];
3431 for (i = 0; i < table->rows; ++i) {
3432 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
3434 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
3435 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
3437 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
3438 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
3440 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
3441 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
3443 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3444 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
3446 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3447 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
3449 /*nested type can't have a namespace*/
3450 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
3451 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
3455 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
3457 verify_manifest_resource_table (VerifyContext *ctx)
3459 MonoCLIImageInfo *iinfo = ctx->image->image_info;
3460 MonoCLIHeader *ch = &iinfo->cli_cli_header;
3461 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
3462 guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
3465 resources_size = ch->ch_resources.size;
3467 for (i = 0; i < table->rows; ++i) {
3468 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
3470 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
3471 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
3473 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
3474 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
3476 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
3477 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
3479 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
3480 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
3482 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3483 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3485 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
3486 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])));
3488 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
3489 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
3491 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
3492 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
3497 verify_nested_class_table (VerifyContext *ctx)
3499 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3500 guint32 data [MONO_NESTED_CLASS_SIZE];
3503 for (i = 0; i < table->rows; ++i) {
3504 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
3506 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3507 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
3508 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3509 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3510 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
3511 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3515 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
3517 verify_generic_param_table (VerifyContext *ctx)
3519 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
3520 guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
3521 int i, param_number = 0;
3523 for (i = 0; i < table->rows; ++i) {
3524 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
3526 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
3527 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
3529 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
3530 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
3532 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
3533 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
3535 token = data [MONO_GENERICPARAM_OWNER];
3537 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
3538 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
3540 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
3541 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
3543 if (token != last_token) {
3548 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
3549 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));
3556 verify_method_spec_table (VerifyContext *ctx)
3558 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3559 guint32 data [MONO_METHODSPEC_SIZE];
3562 for (i = 0; i < table->rows; ++i) {
3563 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3565 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3566 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
3568 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3569 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
3571 if (data [MONO_METHODSPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHODSPEC_SIGNATURE], 1))
3572 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid signature token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3577 verify_method_spec_table_full (VerifyContext *ctx)
3579 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3580 guint32 data [MONO_METHODSPEC_SIZE];
3583 for (i = 0; i < table->rows; ++i) {
3584 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3586 if (!is_valid_methodspec_blob (ctx, data [MONO_METHODSPEC_SIGNATURE]))
3587 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3592 verify_generic_param_constraint_table (VerifyContext *ctx)
3594 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
3595 guint32 data [MONO_GENPARCONSTRAINT_SIZE];
3598 for (i = 0; i < table->rows; ++i) {
3599 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
3601 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
3602 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_TABLE_GENERICPARAM]));
3604 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3605 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
3607 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3608 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
3615 const char *name_space;
3616 guint32 resolution_scope;
3620 typedef_hash (gconstpointer _key)
3622 const TypeDefUniqueId *key = _key;
3623 return g_str_hash (key->name) ^ g_str_hash (key->name_space) ^ key->resolution_scope; /*XXX better salt the int key*/
3627 typedef_equals (gconstpointer _a, gconstpointer _b)
3629 const TypeDefUniqueId *a = _a;
3630 const TypeDefUniqueId *b = _b;
3631 return !strcmp (a->name, b->name) && !strcmp (a->name_space, b->name_space) && a->resolution_scope == b->resolution_scope;
3635 verify_typedef_table_global_constraints (VerifyContext *ctx)
3638 guint32 data [MONO_TYPEDEF_SIZE];
3639 guint32 nested_data [MONO_NESTED_CLASS_SIZE];
3640 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
3641 MonoTableInfo *nested_table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3642 GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3644 for (i = 0; i < table->rows; ++i) {
3646 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3647 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
3649 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAME]);
3650 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAMESPACE]);
3651 type->resolution_scope = 0;
3653 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
3654 if (visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) {
3655 int res = search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1);
3656 g_assert (res >= 0);
3658 mono_metadata_decode_row (nested_table, res, nested_data, MONO_NESTED_CLASS_SIZE);
3659 type->resolution_scope = nested_data [MONO_NESTED_CLASS_ENCLOSING];
3662 if (g_hash_table_lookup (unique_types, type)) {
3663 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("TypeDef table row %d has duplicate for tuple (%s,%s,%x)", i, type->name, type->name_space, type->resolution_scope));
3664 g_hash_table_destroy (unique_types);
3668 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3671 g_hash_table_destroy (unique_types);
3675 verify_typeref_table_global_constraints (VerifyContext *ctx)
3678 guint32 data [MONO_TYPEREF_SIZE];
3679 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
3680 GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3682 for (i = 0; i < table->rows; ++i) {
3683 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3684 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
3686 type->resolution_scope = data [MONO_TYPEREF_SCOPE];
3687 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAME]);
3688 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAMESPACE]);
3690 if (g_hash_table_lookup (unique_types, type)) {
3691 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("TypeRef table row %d has duplicate for tuple (%s,%s,%x)", i, type->name, type->name_space, type->resolution_scope));
3692 g_hash_table_destroy (unique_types);
3696 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3699 g_hash_table_destroy (unique_types);
3703 verify_tables_data_global_constraints (VerifyContext *ctx)
3705 verify_typedef_table_global_constraints (ctx);
3709 verify_tables_data_global_constraints_full (VerifyContext *ctx)
3711 verify_typeref_table (ctx);
3712 verify_typeref_table_global_constraints (ctx);
3716 verify_tables_data (VerifyContext *ctx)
3718 OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
3719 guint32 size = 0, tables_offset;
3722 for (i = 0; i < 0x2D; ++i) {
3723 MonoTableInfo *table = &ctx->image->tables [i];
3725 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
3726 if (tmp_size < size) {
3734 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
3736 tables_offset = ctx->image->tables_base - ctx->data;
3737 if (!bounds_check_offset (&tables_area, tables_offset, size))
3738 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)));
3740 verify_module_table (ctx);
3742 /*Obfuscators love to place broken stuff in the typeref table
3743 verify_typeref_table (ctx);
3745 verify_typedef_table (ctx);
3747 verify_field_table (ctx);
3749 verify_method_table (ctx);
3751 verify_param_table (ctx);
3753 verify_interfaceimpl_table (ctx);
3755 verify_memberref_table (ctx);
3757 verify_constant_table (ctx);
3759 verify_cattr_table (ctx);
3761 verify_field_marshal_table (ctx);
3763 verify_decl_security_table (ctx);
3765 verify_class_layout_table (ctx);
3767 verify_field_layout_table (ctx);
3769 verify_standalonesig_table (ctx);
3771 verify_eventmap_table (ctx);
3773 verify_event_table (ctx);
3775 verify_propertymap_table (ctx);
3777 verify_property_table (ctx);
3779 verify_methodimpl_table (ctx);
3781 verify_moduleref_table (ctx);
3783 verify_typespec_table (ctx);
3785 verify_implmap_table (ctx);
3787 verify_fieldrva_table (ctx);
3789 verify_assembly_table (ctx);
3791 verify_assemblyref_table (ctx);
3793 verify_file_table (ctx);
3795 verify_exportedtype_table (ctx);
3797 verify_manifest_resource_table (ctx);
3799 verify_nested_class_table (ctx);
3801 verify_generic_param_table (ctx);
3803 verify_method_spec_table (ctx);
3805 verify_generic_param_constraint_table (ctx);
3807 verify_tables_data_global_constraints (ctx);
3811 init_verify_context (VerifyContext *ctx, MonoImage *image, gboolean report_error)
3813 memset (ctx, 0, sizeof (VerifyContext));
3815 ctx->report_error = report_error;
3816 ctx->report_warning = FALSE; //export this setting in the API
3818 ctx->size = image->raw_data_len;
3819 ctx->data = image->raw_data;
3823 cleanup_context (VerifyContext *ctx, GSList **error_list)
3825 g_free (ctx->sections);
3827 *error_list = ctx->errors;
3829 mono_free_verify_list (ctx->errors);
3834 cleanup_context_checked (VerifyContext *ctx, MonoError *error)
3836 g_free (ctx->sections);
3838 MonoVerifyInfo *info = ctx->errors->data;
3839 mono_error_set_bad_image (error, ctx->image, "%s", info->message);
3840 mono_free_verify_list (ctx->errors);
3846 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3850 if (!mono_verifier_is_enabled_for_image (image))
3853 init_verify_context (&ctx, image, error_list != NULL);
3854 ctx.stage = STAGE_PE;
3856 verify_msdos_header (&ctx);
3858 verify_pe_header (&ctx);
3860 verify_pe_optional_header (&ctx);
3862 load_section_table (&ctx);
3864 load_data_directories (&ctx);
3866 verify_import_table (&ctx);
3868 /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
3869 verify_resources_table (&ctx);
3872 return cleanup_context (&ctx, error_list);
3876 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3880 if (!mono_verifier_is_enabled_for_image (image))
3883 init_verify_context (&ctx, image, error_list != NULL);
3884 ctx.stage = STAGE_CLI;
3886 verify_cli_header (&ctx);
3888 verify_metadata_header (&ctx);
3890 verify_tables_schema (&ctx);
3893 return cleanup_context (&ctx, error_list);
3898 * Verifies basic table constraints such as global table invariants (sorting, field monotonicity, etc).
3899 * Other verification checks are meant to be done lazily by the runtime. Those include:
3900 * blob items (signatures, method headers, custom attributes, etc)
3901 * type semantics related
3903 * stuff that should not block other pieces from running such as bad types/methods/fields/etc.
3905 * The whole idea is that if this succeed the runtime is free to play around safely but any complex
3906 * operation still need more checking.
3909 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3913 if (!mono_verifier_is_enabled_for_image (image))
3916 init_verify_context (&ctx, image, error_list != NULL);
3917 ctx.stage = STAGE_TABLES;
3919 verify_tables_data (&ctx);
3921 return cleanup_context (&ctx, error_list);
3926 * Verifies all other constraints.
3929 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3933 if (!mono_verifier_is_enabled_for_image (image))
3936 init_verify_context (&ctx, image, error_list != NULL);
3937 ctx.stage = STAGE_TABLES;
3939 verify_typedef_table_full (&ctx);
3941 verify_field_table_full (&ctx);
3943 verify_method_table_full (&ctx);
3945 verify_memberref_table_full (&ctx);
3947 verify_cattr_table_full (&ctx);
3949 verify_field_marshal_table_full (&ctx);
3951 verify_decl_security_table_full (&ctx);
3953 verify_standalonesig_table_full (&ctx);
3955 verify_event_table_full (&ctx);
3957 verify_typespec_table_full (&ctx);
3959 verify_method_spec_table_full (&ctx);
3961 verify_tables_data_global_constraints_full (&ctx);
3964 return cleanup_context (&ctx, error_list);
3968 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
3972 if (!mono_verifier_is_enabled_for_image (image))
3975 init_verify_context (&ctx, image, error_list != NULL);
3976 ctx.stage = STAGE_TABLES;
3978 is_valid_field_signature (&ctx, offset);
3979 return cleanup_context (&ctx, error_list);
3983 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
3986 guint32 locals_token;
3988 if (!mono_verifier_is_enabled_for_image (image))
3991 init_verify_context (&ctx, image, error_list != NULL);
3992 ctx.stage = STAGE_TABLES;
3994 is_valid_method_header (&ctx, offset, &locals_token);
3996 guint32 sig_offset = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_STANDALONESIG], locals_token - 1, MONO_STAND_ALONE_SIGNATURE);
3997 is_valid_standalonesig_blob (&ctx, sig_offset);
4000 return cleanup_context (&ctx, error_list);
4004 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, MonoError *error)
4008 mono_error_init (error);
4010 if (!mono_verifier_is_enabled_for_image (image))
4013 init_verify_context (&ctx, image, TRUE);
4014 ctx.stage = STAGE_TABLES;
4016 is_valid_method_signature (&ctx, offset);
4017 /*XXX This returns a bad image exception, it might be the case that the right exception is method load.*/
4018 return cleanup_context_checked (&ctx, error);
4022 mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
4026 if (!mono_verifier_is_enabled_for_image (image))
4029 init_verify_context (&ctx, image, error_list != NULL);
4030 ctx.stage = STAGE_TABLES;
4032 is_valid_method_or_field_signature (&ctx, offset);
4033 return cleanup_context (&ctx, error_list);
4037 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
4041 if (!mono_verifier_is_enabled_for_image (image))
4044 init_verify_context (&ctx, image, error_list != NULL);
4045 ctx.stage = STAGE_TABLES;
4047 is_valid_standalonesig_blob (&ctx, offset);
4048 return cleanup_context (&ctx, error_list);
4052 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
4056 if (!mono_verifier_is_enabled_for_image (image))
4059 init_verify_context (&ctx, image, error_list != NULL);
4060 ctx.stage = STAGE_TABLES;
4063 is_valid_typespec_blob (&ctx, offset);
4064 return cleanup_context (&ctx, error_list);
4068 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
4072 if (!mono_verifier_is_enabled_for_image (image))
4075 init_verify_context (&ctx, image, error_list != NULL);
4076 ctx.stage = STAGE_TABLES;
4078 is_valid_methodspec_blob (&ctx, offset);
4079 return cleanup_context (&ctx, error_list);
4083 verify_user_string (VerifyContext *ctx, guint32 offset)
4085 OffsetAndSize heap_us = get_metadata_stream (ctx, &ctx->image->heap_us);
4086 guint32 entry_size, bytes;
4088 if (heap_us.size < offset)
4089 ADD_ERROR (ctx, g_strdup ("User string offset beyond heap_us size"));
4091 if (!decode_value (ctx->data + offset + heap_us.offset, heap_us.size - heap_us.offset, &entry_size, &bytes))
4092 ADD_ERROR (ctx, g_strdup ("Could not decode user string blob size"));
4094 if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
4095 ADD_ERROR (ctx, g_strdup ("User string size overflow"));
4097 entry_size += bytes;
4099 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, heap_us.size))
4100 ADD_ERROR (ctx, g_strdup ("User string oveflow heap_us"));
4104 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
4108 if (!mono_verifier_is_enabled_for_image (image))
4111 init_verify_context (&ctx, image, error_list != NULL);
4112 ctx.stage = STAGE_TABLES;
4114 verify_user_string (&ctx, offset);
4116 return cleanup_context (&ctx, error_list);
4120 mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, GSList **error_list)
4124 if (!mono_verifier_is_enabled_for_image (image))
4127 init_verify_context (&ctx, image, error_list != NULL);
4128 ctx.stage = STAGE_TABLES;
4130 is_valid_cattr_blob (&ctx, offset);
4132 return cleanup_context (&ctx, error_list);
4136 mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, GSList **error_list)
4140 if (!mono_verifier_is_enabled_for_image (image))
4143 init_verify_context (&ctx, image, error_list != NULL);
4144 ctx.stage = STAGE_TABLES;
4146 is_valid_cattr_content (&ctx, ctor, (const char*)data, size);
4148 return cleanup_context (&ctx, error_list);
4152 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
4154 MonoMethodSignature *original_sig;
4155 if (!mono_verifier_is_enabled_for_image (image))
4158 original_sig = mono_method_signature (method);
4159 if (original_sig->call_convention == MONO_CALL_VARARG) {
4160 if (original_sig->hasthis != signature->hasthis)
4162 if (original_sig->call_convention != signature->call_convention)
4164 if (original_sig->explicit_this != signature->explicit_this)
4166 if (original_sig->call_convention != signature->call_convention)
4168 if (original_sig->pinvoke != signature->pinvoke)
4170 if (original_sig->sentinelpos != signature->sentinelpos)
4172 } else if (!mono_metadata_signature_equal (signature, original_sig)) {
4180 mono_verifier_verify_typeref_row (MonoImage *image, guint32 row, MonoError *error)
4182 MonoTableInfo *table = &image->tables [MONO_TABLE_TYPEREF];
4183 guint32 data [MONO_TYPEREF_SIZE];
4185 mono_error_init (error);
4187 if (!mono_verifier_is_enabled_for_image (image))
4190 if (row >= table->rows) {
4191 mono_error_set_bad_image (error, image, "Invalid typeref row %d - table has %d rows", row, table->rows);
4195 mono_metadata_decode_row (table, row, data, MONO_TYPEREF_SIZE);
4196 if (!is_valid_coded_index_with_image (image, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE])) {
4197 mono_error_set_bad_image (error, image, "Invalid typeref row %d coded index 0x%08x", row, data [MONO_TYPEREF_SCOPE]);
4201 if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE])) {
4202 mono_error_set_bad_image (error, image, "The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", row);
4206 if (!data [MONO_TYPEREF_NAME] || !is_valid_string_full_with_image (image, data [MONO_TYPEREF_NAME], FALSE)) {
4207 mono_error_set_bad_image (error, image, "Invalid typeref row %d name token 0x%08x", row, data [MONO_TYPEREF_NAME]);
4211 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_string_full_with_image (image, data [MONO_TYPEREF_NAMESPACE], FALSE)) {
4212 mono_error_set_bad_image (error, image, "Invalid typeref row %d namespace token 0x%08x", row, data [MONO_TYPEREF_NAMESPACE]);
4219 /*Perform additional verification including metadata ones*/
4221 mono_verifier_verify_methodimpl_row (MonoImage *image, guint32 row, MonoError *error)
4223 MonoMethod *declaration, *body;
4224 MonoMethodSignature *body_sig, *decl_sig;
4225 MonoTableInfo *table = &image->tables [MONO_TABLE_METHODIMPL];
4226 guint32 data [MONO_METHODIMPL_SIZE];
4228 mono_error_init (error);
4230 if (!mono_verifier_is_enabled_for_image (image))
4233 if (row >= table->rows) {
4234 mono_error_set_bad_image (error, image, "Invalid methodimpl row %d - table has %d rows", row, table->rows);
4238 mono_metadata_decode_row (table, row, data, MONO_METHODIMPL_SIZE);
4240 body = method_from_method_def_or_ref (image, data [MONO_METHODIMPL_BODY], NULL);
4241 if (mono_loader_get_last_error ()) {
4242 mono_loader_clear_error ();
4243 mono_error_set_bad_image (error, image, "Invalid methodimpl body for row %x", row);
4247 declaration = method_from_method_def_or_ref (image, data [MONO_METHODIMPL_DECLARATION], NULL);
4248 if (mono_loader_get_last_error ()) {
4249 mono_loader_clear_error ();
4250 mono_error_set_bad_image (error, image, "Invalid methodimpl declaration for row %x", row);
4255 mono_class_setup_supertypes (class);
4256 if (!mono_class_has_parent (class, body->klass)) {
4257 mono_error_set_bad_image (error, image, "Invalid methodimpl body doesn't belong to parent for row %x", row);
4261 if (!(body_sig = mono_method_signature_checked (body, error))) {
4265 if (!(decl_sig = mono_method_signature_checked (declaration, error))) {
4269 if (!mono_verifier_is_signature_compatible (decl_sig, body_sig)) {
4270 mono_error_set_bad_image (error, image, "Invalid methodimpl body signature not compatible with declaration row %x", row);
4279 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
4285 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
4291 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
4297 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
4303 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4309 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
4315 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, MonoError *error)
4317 mono_error_init (error);
4322 mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
4328 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
4334 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
4340 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
4346 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
4352 mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, GSList **error_list)
4358 mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, GSList **error_list)
4364 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
4371 mono_verifier_verify_typeref_row (MonoImage *image, guint32 row, MonoError *error)
4373 mono_error_init (error);
4378 mono_verifier_verify_methodimpl_row (MonoImage *image, guint32 row, MonoError *error)
4380 mono_error_init (error);
4384 #endif /* DISABLE_VERIFIER */