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 == 0x50 || etype == MONO_TYPE_CLASS) {
1860 klass = mono_defaults.systemtype_class;
1861 } else if ((etype >= MONO_TYPE_BOOLEAN && etype <= MONO_TYPE_STRING) || etype == 0x51) {
1862 simple_type.type = etype == 0x51 ? MONO_TYPE_OBJECT : etype;
1863 klass = mono_class_from_mono_type (&simple_type);
1865 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype));
1867 type = MONO_TYPE_SZARRAY;
1870 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid boxed object type %x", sub_type));
1874 case MONO_TYPE_CLASS:
1875 if (klass != mono_defaults.systemtype_class)
1876 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid class parameter type %s:%s ",klass->name_space, klass->name));
1878 return is_valid_ser_string (ctx, _ptr, end);
1880 case MONO_TYPE_VALUETYPE:
1881 if (!klass || !klass->enumtype)
1882 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid valuetype parameter expected enum %s:%s ",klass->name_space, klass->name));
1884 klass = klass->element_class;
1885 type = klass->byval_arg.type;
1888 case MONO_TYPE_SZARRAY:
1889 mono_type = &klass->byval_arg;
1890 if (!is_valid_cattr_type (mono_type))
1891 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %s:%s ",klass->name_space, klass->name));
1892 if (!safe_read32 (element_count, ptr, end))
1893 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid class parameter type %s:%s ",klass->name_space, klass->name));
1894 if (element_count == 0xFFFFFFFFu) {
1898 for (i = 0; i < element_count; ++i) {
1899 if (!is_valid_fixed_param (ctx, mono_type, &ptr, end))
1905 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid parameter type %x ", type));
1908 if (ADDP_IS_GREATER_OR_OVF (ptr, elem_size, end))
1909 FAIL (ctx, g_strdup ("CustomAttribute: Not enough space for element"));
1910 *_ptr = ptr + elem_size;
1915 is_valid_cattr_content (VerifyContext *ctx, MonoMethod *ctor, const char *ptr, guint32 size)
1918 unsigned prolog = 0;
1920 MonoMethodSignature *sig;
1925 FAIL (ctx, g_strdup ("CustomAttribute: Invalid constructor"));
1927 sig = mono_method_signature_checked (ctor, &error);
1928 if (!mono_error_ok (&error)) {
1929 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute: Invalid constructor signature %s", mono_error_get_message (&error)));
1930 mono_error_cleanup (&error);
1934 if (sig->sentinelpos != -1 || sig->call_convention == MONO_CALL_VARARG)
1935 FAIL (ctx, g_strdup ("CustomAttribute: Constructor cannot have VARAG signature"));
1939 if (!safe_read16 (prolog, ptr, end))
1940 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1943 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1945 args = sig->param_count;
1946 for (i = 0; i < args; ++i) {
1947 MonoType *arg_type = sig->params [i];
1948 if (!is_valid_fixed_param (ctx, arg_type, &ptr, end))
1952 if (!safe_read16 (num_named, ptr, end))
1953 FAIL (ctx, g_strdup ("CustomAttribute: Not enough space for num_named field"));
1955 for (i = 0; i < num_named; ++i) {
1956 MonoType *type, simple_type = {{0}};
1959 if (!safe_read8 (kind, ptr, end))
1960 FAIL (ctx, g_strdup_printf ("CustomAttribute: Not enough space for named parameter %d kind", i));
1961 if (kind != 0x53 && kind != 0x54)
1962 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid named parameter %d kind %x", i, kind));
1963 if (!safe_read8 (kind, ptr, end))
1964 FAIL (ctx, g_strdup_printf ("CustomAttribute: Not enough space for named parameter %d type", i));
1966 if (kind >= MONO_TYPE_BOOLEAN && kind <= MONO_TYPE_STRING) {
1967 simple_type.type = kind;
1968 type = &simple_type;
1969 } else if (kind == MONO_TYPE_ENUM) {
1970 MonoClass *klass = get_enum_by_encoded_name (ctx, &ptr, end);
1973 type = &klass->byval_arg;
1974 } else if (kind == 0x50) {
1975 type = &mono_defaults.systemtype_class->byval_arg;
1976 } else if (kind == 0x51) {
1977 type = &mono_defaults.object_class->byval_arg;
1978 } else if (kind == MONO_TYPE_SZARRAY) {
1981 if (!safe_read8 (etype, ptr, end))
1982 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array element type"));
1984 if (etype == MONO_TYPE_ENUM) {
1985 klass = get_enum_by_encoded_name (ctx, &ptr, end);
1988 } else if (etype == 0x50 || etype == MONO_TYPE_CLASS) {
1989 klass = mono_defaults.systemtype_class;
1990 } else if ((etype >= MONO_TYPE_BOOLEAN && etype <= MONO_TYPE_STRING) || etype == 0x51) {
1991 simple_type.type = etype == 0x51 ? MONO_TYPE_OBJECT : etype;
1992 klass = mono_class_from_mono_type (&simple_type);
1994 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype));
1996 type = &mono_array_class_get (klass, 1)->byval_arg;
1998 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid named parameter type %x", kind));
2001 if (!is_valid_ser_string (ctx, &ptr, end))
2004 if (!is_valid_fixed_param (ctx, type, &ptr, end))
2013 is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
2015 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2016 //TODO do proper verification
2017 return blob.size >= 1 && blob.size - 1 >= offset;
2021 is_valid_permission_set (VerifyContext *ctx, guint32 offset)
2023 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2024 //TODO do proper verification
2025 return blob.size >= 1 && blob.size - 1 >= offset;
2029 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
2032 unsigned signature = 0;
2033 const char *ptr = NULL, *end;
2035 if (!decode_signature_header (ctx, offset, &size, &ptr))
2036 FAIL (ctx, g_strdup ("StandAloneSig: Could not decode signature header"));
2039 if (!safe_read8 (signature, ptr, end))
2040 FAIL (ctx, g_strdup ("StandAloneSig: Not enough room for the call conv"));
2043 if (signature == 0x07)
2044 return parse_locals_signature (ctx, &ptr, end);
2046 /*F# and managed C++ produce standalonesig for fields even thou the spec doesn't mention it.*/
2047 if (signature == 0x06)
2048 return parse_field (ctx, &ptr, end);
2050 return parse_method_signature (ctx, &ptr, end, TRUE, TRUE);
2054 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
2057 const char *ptr = NULL, *end;
2059 if (!decode_signature_header (ctx, offset, &size, &ptr))
2060 FAIL (ctx, g_strdup ("PropertySig: Could not decode signature header"));
2063 return parse_property_signature (ctx, &ptr, end);
2067 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
2070 const char *ptr = NULL, *end;
2073 if (!decode_signature_header (ctx, offset, &size, &ptr))
2074 FAIL (ctx, g_strdup ("TypeSpec: Could not decode signature header"));
2077 if (!parse_custom_mods (ctx, &ptr, end))
2080 if (!safe_read8 (type, ptr, end))
2081 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for type"));
2083 if (type == MONO_TYPE_BYREF) {
2084 if (!safe_read8 (type, ptr, end))
2085 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for byref type"));
2086 if (type == MONO_TYPE_TYPEDBYREF)
2087 FAIL (ctx, g_strdup ("TypeSpec: Invalid type typedref&"));
2090 if (type == MONO_TYPE_TYPEDBYREF)
2094 return parse_type (ctx, &ptr, end);
2098 is_valid_methodspec_blob (VerifyContext *ctx, guint32 offset)
2101 const char *ptr = NULL, *end;
2103 unsigned count = 0, i;
2105 if (!decode_signature_header (ctx, offset, &size, &ptr))
2106 FAIL (ctx, g_strdup ("MethodSpec: Could not decode signature header"));
2109 if (!safe_read8 (type, ptr, end))
2110 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for call convention"));
2113 FAIL (ctx, g_strdup_printf ("MethodSpec: Invalid call convention 0x%x, expected 0x0A", type));
2115 if (!safe_read_cint (count, ptr, end))
2116 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for parameter count"));
2119 FAIL (ctx, g_strdup ("MethodSpec: Zero generic argument count"));
2121 for (i = 0; i < count; ++i) {
2122 if (!parse_type (ctx, &ptr, end))
2123 FAIL (ctx, g_strdup_printf ("MethodSpec: Could not parse parameter %d", i + 1));
2129 is_valid_blob_object (VerifyContext *ctx, guint32 offset, guint32 minsize)
2131 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2132 guint32 entry_size, bytes;
2134 if (blob.size < offset)
2137 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
2140 if (entry_size < minsize)
2143 if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
2145 entry_size += bytes;
2147 return !ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size);
2151 is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
2153 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2154 guint32 size, entry_size, bytes;
2156 if (blob.size < offset)
2157 FAIL (ctx, g_strdup ("ContantValue: invalid offset"));
2159 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
2160 FAIL (ctx, g_strdup ("ContantValue: not enough space to decode size"));
2162 if (type == MONO_TYPE_STRING) {
2163 //String is encoded as: compressed_int:len len *bytes
2166 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size))
2167 FAIL (ctx, g_strdup_printf ("ContantValue: not enough space for string, required %d but got %d", entry_size * 2, blob.size - offset));
2173 case MONO_TYPE_BOOLEAN:
2178 case MONO_TYPE_CHAR:
2186 case MONO_TYPE_CLASS:
2196 g_assert_not_reached ();
2199 if (size != entry_size)
2200 FAIL (ctx, g_strdup_printf ("ContantValue: Expected size %d but got %d", size, entry_size));
2204 if (ADD_IS_GREATER_OR_OVF (offset, size, blob.size))
2205 FAIL (ctx, g_strdup_printf ("ContantValue: Not enough room for constant, required %d but have %d", size, blob.size - offset));
2207 if (type == MONO_TYPE_CLASS && read32 (ctx->data + blob.offset + offset))
2208 FAIL (ctx, g_strdup_printf ("ContantValue: Type is class but value is not null"));
2212 #define FAT_HEADER_INVALID_FLAGS ~(0x3 | 0x8 | 0x10 | 0xF000)
2213 //only 0x01, 0x40 and 0x80 are allowed
2214 #define SECTION_HEADER_INVALID_FLAGS 0x3E
2217 is_valid_method_header (VerifyContext *ctx, guint32 rva, guint32 *locals_token)
2219 unsigned local_vars_tok, code_size, offset = mono_cli_rva_image_map (ctx->image, rva);
2220 unsigned header = 0;
2221 unsigned fat_header = 0, size = 0, max_stack;
2222 const char *ptr = NULL, *end;
2226 if (offset == INVALID_ADDRESS)
2227 FAIL (ctx, g_strdup ("MethodHeader: Invalid RVA"));
2229 ptr = ctx->data + offset;
2230 end = ctx->data + ctx->size; /*no worries if it spawns multiple sections*/
2232 if (!safe_read8 (header, ptr, end))
2233 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for header"));
2235 switch (header & 0x3) {
2238 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid header type 0x%x", header & 0x3));
2241 if (ADDP_IS_GREATER_OR_OVF (ptr, header, end))
2242 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for method body. Required %d, but only %d is available", header, (int)(end - ptr)));
2247 if (!safe_read16 (fat_header, ptr, end))
2248 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for fat header"));
2250 size = (fat_header >> 12) & 0xF;
2252 FAIL (ctx, g_strdup ("MethodHeader: header size must be 3"));
2254 if (!safe_read16 (max_stack, ptr, end))
2255 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for max stack"));
2257 if (!safe_read32 (code_size, ptr, end))
2258 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for code size"));
2260 if (!safe_read32 (local_vars_tok, ptr, end))
2261 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for local vars tok"));
2263 if (local_vars_tok) {
2264 if (((local_vars_tok >> 24) & 0xFF) != 0x11)
2265 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature table 0x%x", ((local_vars_tok >> 24) & 0xFF)));
2266 if ((local_vars_tok & 0xFFFFFF) > ctx->image->tables [MONO_TABLE_STANDALONESIG].rows)
2267 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature points to invalid row 0x%x", local_vars_tok & 0xFFFFFF));
2268 if (!(local_vars_tok & 0xFFFFFF))
2269 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature with zero index"));
2270 *locals_token = local_vars_tok & 0xFFFFFF;
2273 if (fat_header & FAT_HEADER_INVALID_FLAGS)
2274 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid fat signature flags %x", fat_header & FAT_HEADER_INVALID_FLAGS));
2276 if (ADDP_IS_GREATER_OR_OVF (ptr, code_size, end))
2277 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for code %d", code_size));
2279 if (!(fat_header & 0x08))
2285 unsigned section_header = 0, section_size = 0;
2288 ptr = dword_align (ptr);
2289 if (!safe_read32 (section_header, ptr, end))
2290 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for data section header"));
2292 if (section_header & SECTION_HEADER_INVALID_FLAGS)
2293 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section header flags 0x%x", section_header & SECTION_HEADER_INVALID_FLAGS));
2295 is_fat = (section_header & METHOD_HEADER_SECTION_FAT_FORMAT) != 0;
2296 section_size = (section_header >> 8) & (is_fat ? 0xFFFFFF : 0xFF);
2298 if (section_size < 4)
2299 FAIL (ctx, g_strdup_printf ("MethodHeader: Section size too small"));
2301 if (ADDP_IS_GREATER_OR_OVF (ptr, section_size - 4, end)) /*must be section_size -4 as ptr was incremented by safe_read32*/
2302 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section content %d", section_size));
2304 if (section_header & METHOD_HEADER_SECTION_EHTABLE) {
2305 guint32 i, clauses = section_size / (is_fat ? 24 : 12);
2307 LAMEIMPL: MS emits section_size without accounting for header size.
2308 Mono does as the spec says. section_size is header + section
2309 MS's peverify happily accepts both.
2311 if ((clauses * (is_fat ? 24 : 12) != section_size) && (clauses * (is_fat ? 24 : 12) + 4 != section_size))
2312 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)));
2314 /* only verify the class token is verified as the rest is done by the IL verifier*/
2315 for (i = 0; i < clauses; ++i) {
2316 unsigned flags = *(unsigned char*)ptr;
2317 unsigned class_token = 0;
2318 ptr += (is_fat ? 20 : 8);
2319 if (!safe_read32 (class_token, ptr, end))
2320 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section %d", i));
2321 if (flags == MONO_EXCEPTION_CLAUSE_NONE && class_token) {
2322 guint table = mono_metadata_token_table (class_token);
2323 if (table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPESPEC)
2324 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token table %x", i, table));
2325 if (mono_metadata_token_index (class_token) > ctx->image->tables [table].rows)
2326 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token index %x", i, mono_metadata_token_index (class_token)));
2331 if (!(section_header & METHOD_HEADER_SECTION_MORE_SECTS))
2338 verify_module_table (VerifyContext *ctx)
2340 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
2341 guint32 data [MONO_MODULE_SIZE];
2343 if (table->rows != 1)
2344 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
2346 mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
2348 if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
2349 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
2351 if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
2352 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
2354 if (data [MONO_MODULE_ENC] != 0)
2355 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
2357 if (data [MONO_MODULE_ENCBASE] != 0)
2358 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
2362 verify_typeref_table (VerifyContext *ctx)
2364 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
2368 for (i = 0; i < table->rows; ++i) {
2369 mono_verifier_verify_typeref_row (ctx->image, i, &error);
2370 add_from_mono_error (ctx, &error);
2374 /*bits 9,11,14,15,19,21,24-31 */
2375 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 14) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
2377 verify_typedef_table (VerifyContext *ctx)
2379 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2380 guint32 data [MONO_TYPEDEF_SIZE];
2381 guint32 fieldlist = 1, methodlist = 1, visibility;
2384 if (table->rows == 0)
2385 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2387 for (i = 0; i < table->rows; ++i) {
2388 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2389 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
2390 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
2392 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
2393 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
2395 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
2396 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2398 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
2399 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2401 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) && (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
2402 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
2404 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
2405 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
2407 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
2408 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
2410 if (data [MONO_TYPEDEF_EXTENDS] && !is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
2411 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
2413 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
2414 if ((visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) &&
2415 search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1) == -1)
2416 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d has nested visibility but no rows in the NestedClass table", i));
2418 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
2419 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
2421 if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2422 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
2424 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
2425 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));
2427 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
2428 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
2430 if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
2431 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
2433 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
2434 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));
2436 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
2437 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
2442 verify_typedef_table_full (VerifyContext *ctx)
2444 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2445 guint32 data [MONO_TYPEDEF_SIZE];
2448 if (table->rows == 0)
2449 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2451 for (i = 0; i < table->rows; ++i) {
2452 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2455 /*XXX it's ok if <module> extends object, or anything at all, actually. */
2456 /*if (data [MONO_TYPEDEF_EXTENDS] != 0)
2457 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
2462 if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
2463 if (data [MONO_TYPEDEF_EXTENDS])
2464 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
2466 gboolean is_sys_obj = typedef_is_system_object (ctx, data);
2467 gboolean has_parent = get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]) != 0;
2471 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
2474 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
2482 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
2484 verify_field_table (VerifyContext *ctx)
2486 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2487 guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
2490 module_field_list = (guint32)-1;
2491 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2492 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2493 module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
2496 for (i = 0; i < table->rows; ++i) {
2497 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2498 flags = data [MONO_FIELD_FLAGS];
2500 if (flags & INVALID_FIELD_FLAG_BITS)
2501 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
2503 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)
2504 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
2506 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
2507 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
2509 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
2510 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
2512 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
2513 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
2515 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
2516 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
2517 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
2519 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
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 has Default but there is no corresponding row in the Constant table", i));
2523 if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
2524 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2525 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
2527 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
2528 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
2529 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2531 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
2532 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
2534 if (data [MONO_FIELD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_FIELD_SIGNATURE], 1))
2535 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature blob token 0x%x", i, data [MONO_FIELD_SIGNATURE]));
2537 //TODO verify contant flag
2539 if (i + 1 < module_field_list) {
2540 guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
2541 if (!(flags & FIELD_ATTRIBUTE_STATIC))
2542 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
2543 if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
2544 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
2550 verify_field_table_full (VerifyContext *ctx)
2552 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2553 guint32 data [MONO_FIELD_SIZE];
2556 for (i = 0; i < table->rows; ++i) {
2557 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2559 if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
2560 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
2564 /*bits 8,9,10,11,13,14,15*/
2565 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
2567 verify_method_table (VerifyContext *ctx)
2569 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2570 guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
2571 guint32 paramlist = 1;
2572 gboolean is_ctor, is_cctor;
2576 module_method_list = (guint32)-1;
2577 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2578 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2579 module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
2582 for (i = 0; i < table->rows; ++i) {
2583 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2584 rva = data [MONO_METHOD_RVA];
2585 implflags = data [MONO_METHOD_IMPLFLAGS];
2586 flags = data [MONO_METHOD_FLAGS];
2587 access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
2588 code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
2591 if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
2592 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
2595 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
2597 if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
2598 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
2600 name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
2601 is_ctor = !strcmp (".ctor", name);
2602 is_cctor = !strcmp (".cctor", name);
2604 if ((is_ctor || is_cctor) &&
2605 search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
2606 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
2608 if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
2609 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
2611 if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
2612 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
2613 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
2614 if (flags & METHOD_ATTRIBUTE_FINAL)
2615 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and Final", i));
2616 if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
2617 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
2620 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
2621 ADD_WARNING (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
2623 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
2624 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
2626 //XXX no checks against cas stuff 10,11,12,13)
2628 //TODO check iface with .ctor (15,16)
2630 if (i + 1 < module_method_list) {
2631 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2632 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
2633 if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
2634 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
2635 if (!(access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED || access == METHOD_ATTRIBUTE_PUBLIC || access == METHOD_ATTRIBUTE_PRIVATE))
2636 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public or Private", i));
2639 //TODO check valuetype for synchronized
2641 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
2642 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
2644 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
2645 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
2646 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
2647 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2648 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but not Static", i));
2651 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
2652 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2653 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
2655 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
2656 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
2658 //TODO check signature contents
2661 if (flags & METHOD_ATTRIBUTE_ABSTRACT)
2662 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", i));
2663 if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
2664 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
2666 if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2667 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
2670 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2672 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
2673 if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
2674 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
2676 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
2677 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
2679 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
2680 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
2682 if (data [MONO_METHOD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHOD_SIGNATURE], 1))
2683 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature blob token 0x%x", i, data [MONO_METHOD_SIGNATURE]));
2685 if (data [MONO_METHOD_PARAMLIST] == 0)
2686 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
2688 if (data [MONO_METHOD_PARAMLIST] < paramlist)
2689 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));
2691 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
2692 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
2694 paramlist = data [MONO_METHOD_PARAMLIST];
2700 verify_method_table_full (VerifyContext *ctx)
2702 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2703 guint32 data [MONO_METHOD_SIZE], rva, locals_token;
2706 for (i = 0; i < table->rows; ++i) {
2707 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2708 rva = data [MONO_METHOD_RVA];
2710 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
2711 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
2713 if (rva && !is_valid_method_header (ctx, rva, &locals_token))
2714 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
2719 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
2721 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2722 guint32 row = *current_method;
2723 guint32 paramlist, tmp;
2726 paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
2727 while (row < table->rows) {
2728 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
2729 if (tmp > paramlist) {
2730 *current_method = row;
2731 return tmp - paramlist;
2736 /*no more methods, all params apply to the last one*/
2737 *current_method = table->rows;
2742 #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))
2744 verify_param_table (VerifyContext *ctx)
2746 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
2747 guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
2748 gboolean first_param = TRUE;
2751 if (ctx->image->tables [MONO_TABLE_METHOD].rows == 0) {
2752 if (table->rows > 0)
2753 ADD_ERROR (ctx, g_strdup ("Param table has rows while the method table has zero"));
2757 remaining_params = get_next_param_count (ctx, ¤t_method);
2759 for (i = 0; i < table->rows; ++i) {
2760 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
2761 flags = data [MONO_PARAM_FLAGS];
2763 if (flags & INVALID_PARAM_FLAGS_BITS)
2764 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
2766 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
2767 if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
2768 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
2770 if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
2771 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
2774 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)
2775 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
2777 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
2778 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
2780 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
2781 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
2783 first_param = FALSE;
2784 sequence = data [MONO_PARAM_SEQUENCE];
2785 if (--remaining_params == 0) {
2786 remaining_params = get_next_param_count (ctx, ¤t_method);
2793 verify_interfaceimpl_table (VerifyContext *ctx)
2795 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
2796 guint32 data [MONO_INTERFACEIMPL_SIZE];
2799 for (i = 0; i < table->rows; ++i) {
2800 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
2801 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2802 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2804 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2805 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
2807 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2808 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
2813 verify_memberref_table (VerifyContext *ctx)
2815 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2816 guint32 data [MONO_MEMBERREF_SIZE];
2819 for (i = 0; i < table->rows; ++i) {
2820 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2822 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2823 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
2825 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2826 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
2828 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
2829 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
2831 if (data [MONO_MEMBERREF_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_MEMBERREF_SIGNATURE], 1))
2832 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d invalid signature blob token 0x%x", i, data [MONO_MEMBERREF_SIGNATURE]));
2838 verify_memberref_table_full (VerifyContext *ctx)
2840 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2841 guint32 data [MONO_MEMBERREF_SIZE];
2844 for (i = 0; i < table->rows; ++i) {
2845 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2847 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
2848 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field 0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
2853 verify_constant_table (VerifyContext *ctx)
2855 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
2856 guint32 data [MONO_CONSTANT_SIZE], type;
2859 for (i = 0; i < table->rows; ++i) {
2860 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
2861 type = data [MONO_CONSTANT_TYPE];
2863 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
2864 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
2866 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2867 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
2869 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2870 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
2872 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
2873 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
2878 verify_cattr_table (VerifyContext *ctx)
2880 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2881 guint32 data [MONO_CUSTOM_ATTR_SIZE];
2884 for (i = 0; i < table->rows; ++i) {
2885 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2887 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
2888 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2890 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]))
2891 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Type field 0x%08x", i, data [MONO_CUSTOM_ATTR_TYPE]));
2893 if (data [MONO_CUSTOM_ATTR_VALUE] && !is_valid_blob_object (ctx, data [MONO_CUSTOM_ATTR_VALUE], 0))
2894 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d invalid value blob 0x%x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2899 verify_cattr_table_full (VerifyContext *ctx)
2901 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2904 guint32 data [MONO_CUSTOM_ATTR_SIZE], mtoken, size;
2907 for (i = 0; i < table->rows; ++i) {
2908 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2910 if (!is_valid_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
2911 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2913 mtoken = data [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
2914 switch (data [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
2915 case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
2916 mtoken |= MONO_TOKEN_METHOD_DEF;
2918 case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
2919 mtoken |= MONO_TOKEN_MEMBER_REF;
2922 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute constructor row %d Token 0x%08x", i, data [MONO_CUSTOM_ATTR_TYPE]));
2925 ctor = mono_get_method (ctx->image, mtoken, NULL);
2927 /*This can't fail since this is checked in is_valid_cattr_blob*/
2928 g_assert (decode_signature_header (ctx, data [MONO_CUSTOM_ATTR_VALUE], &size, &ptr));
2930 if (!is_valid_cattr_content (ctx, ctor, ptr, size))
2931 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute content row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2936 verify_field_marshal_table (VerifyContext *ctx)
2938 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2939 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2942 for (i = 0; i < table->rows; ++i) {
2943 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2945 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2946 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
2948 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2949 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
2951 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
2952 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
2954 if (!is_valid_blob_object (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE], 1))
2955 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d invalid NativeType blob 0x%x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2960 verify_field_marshal_table_full (VerifyContext *ctx)
2962 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2963 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2966 for (i = 0; i < table->rows; ++i) {
2967 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2969 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
2970 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2975 verify_decl_security_table (VerifyContext *ctx)
2977 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2978 guint32 data [MONO_DECL_SECURITY_SIZE];
2981 for (i = 0; i < table->rows; ++i) {
2982 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2984 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2985 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
2987 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2988 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
2990 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
2991 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
2996 verify_decl_security_table_full (VerifyContext *ctx)
2998 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2999 guint32 data [MONO_DECL_SECURITY_SIZE];
3002 for (i = 0; i < table->rows; ++i) {
3003 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
3005 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
3006 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
3011 verify_class_layout_table (VerifyContext *ctx)
3013 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
3014 guint32 data [MONO_CLASS_LAYOUT_SIZE];
3017 for (i = 0; i < table->rows; ++i) {
3018 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
3020 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3021 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
3023 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
3035 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
3041 verify_field_layout_table (VerifyContext *ctx)
3043 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
3044 guint32 data [MONO_FIELD_LAYOUT_SIZE];
3047 for (i = 0; i < table->rows; ++i) {
3048 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
3050 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
3051 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
3056 verify_standalonesig_table (VerifyContext *ctx)
3058 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
3059 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
3062 for (i = 0; i < table->rows; ++i) {
3063 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
3065 if (data [MONO_STAND_ALONE_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_STAND_ALONE_SIGNATURE], 1))
3066 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d invalid signature 0x%x", i, data [MONO_STAND_ALONE_SIGNATURE]));
3071 verify_standalonesig_table_full (VerifyContext *ctx)
3073 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
3074 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
3077 for (i = 0; i < table->rows; ++i) {
3078 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
3080 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
3081 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
3086 verify_eventmap_table (VerifyContext *ctx)
3088 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
3089 guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
3092 for (i = 0; i < table->rows; ++i) {
3093 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
3095 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3096 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
3098 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
3099 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
3101 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
3105 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
3107 verify_event_table (VerifyContext *ctx)
3109 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
3110 guint32 data [MONO_EVENT_SIZE];
3113 for (i = 0; i < table->rows; ++i) {
3114 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
3116 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
3117 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
3119 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
3120 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
3122 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
3123 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
3128 verify_event_table_full (VerifyContext *ctx)
3130 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
3131 MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
3132 guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
3133 gboolean found_add, found_remove;
3136 for (i = 0; i < table->rows; ++i) {
3137 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
3139 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
3140 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
3142 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
3144 //first we move to the first row for this event
3146 if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
3150 //now move forward looking for AddOn and RemoveOn rows
3151 found_add = found_remove = FALSE;
3152 while (idx < sema_table->rows) {
3153 mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
3154 if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
3156 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
3158 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
3159 found_remove = TRUE;
3160 if (found_add && found_remove)
3166 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
3168 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
3173 verify_propertymap_table (VerifyContext *ctx)
3175 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
3176 guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
3179 for (i = 0; i < table->rows; ++i) {
3180 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
3182 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3183 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
3185 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
3186 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
3188 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
3192 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
3194 verify_property_table (VerifyContext *ctx)
3196 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
3197 guint32 data [MONO_PROPERTY_SIZE];
3200 for (i = 0; i < table->rows; ++i) {
3201 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
3203 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
3204 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
3206 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
3207 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
3209 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
3210 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
3212 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
3213 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
3214 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
3220 verify_methodimpl_table (VerifyContext *ctx)
3222 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
3223 guint32 data [MONO_METHODIMPL_SIZE];
3226 for (i = 0; i < table->rows; ++i) {
3227 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
3229 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3230 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
3232 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
3233 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
3235 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
3236 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
3238 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
3239 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
3241 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
3242 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
3247 verify_moduleref_table (VerifyContext *ctx)
3249 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
3250 guint32 data [MONO_MODULEREF_SIZE];
3253 for (i = 0; i < table->rows; ++i) {
3254 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
3256 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
3257 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
3262 verify_typespec_table (VerifyContext *ctx)
3264 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
3265 guint32 data [MONO_TYPESPEC_SIZE];
3268 for (i = 0; i < table->rows; ++i) {
3269 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
3271 if (data [MONO_TYPESPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_TYPESPEC_SIGNATURE], 1))
3272 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
3277 verify_typespec_table_full (VerifyContext *ctx)
3279 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
3280 guint32 data [MONO_TYPESPEC_SIZE];
3283 for (i = 0; i < table->rows; ++i) {
3284 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
3285 ctx->token = (i + 1) | MONO_TOKEN_TYPE_SPEC;
3286 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
3287 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
3292 #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))
3294 verify_implmap_table (VerifyContext *ctx)
3296 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
3297 guint32 data [MONO_IMPLMAP_SIZE], cconv;
3300 for (i = 0; i < table->rows; ++i) {
3301 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
3303 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
3304 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
3306 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
3307 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
3308 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
3310 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
3311 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
3313 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
3314 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
3316 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
3317 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
3319 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
3320 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
3322 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULEREF].rows)
3323 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
3328 verify_fieldrva_table (VerifyContext *ctx)
3330 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
3331 guint32 data [MONO_FIELD_RVA_SIZE];
3334 for (i = 0; i < table->rows; ++i) {
3335 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
3337 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
3338 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
3340 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
3341 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
3345 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 4) | (1 << 8) | (1 << 14) | (1 << 15))
3347 verify_assembly_table (VerifyContext *ctx)
3349 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
3350 guint32 data [MONO_ASSEMBLY_SIZE], hash;
3353 if (table->rows > 1)
3354 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
3356 for (i = 0; i < table->rows; ++i) {
3357 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
3359 hash = data [MONO_ASSEMBLY_HASH_ALG];
3360 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
3361 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
3363 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
3364 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
3366 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY], 1))
3367 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
3369 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
3370 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
3372 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
3373 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
3377 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~(1)
3379 verify_assemblyref_table (VerifyContext *ctx)
3381 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
3382 guint32 data [MONO_ASSEMBLYREF_SIZE];
3385 for (i = 0; i < table->rows; ++i) {
3386 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
3388 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
3389 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
3391 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY], 1))
3392 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
3394 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
3395 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
3397 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
3398 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
3400 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE], 1))
3401 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
3405 #define INVALID_FILE_FLAGS_BITS ~(1)
3407 verify_file_table (VerifyContext *ctx)
3409 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
3410 guint32 data [MONO_FILE_SIZE];
3413 for (i = 0; i < table->rows; ++i) {
3414 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
3416 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
3417 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
3419 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
3420 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
3422 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE], 1))
3423 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
3427 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
3429 verify_exportedtype_table (VerifyContext *ctx)
3431 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
3432 guint32 data [MONO_EXP_TYPE_SIZE];
3435 for (i = 0; i < table->rows; ++i) {
3436 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
3438 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
3439 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
3441 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
3442 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
3444 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
3445 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
3447 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3448 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
3450 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3451 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
3453 /*nested type can't have a namespace*/
3454 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
3455 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
3459 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
3461 verify_manifest_resource_table (VerifyContext *ctx)
3463 MonoCLIImageInfo *iinfo = ctx->image->image_info;
3464 MonoCLIHeader *ch = &iinfo->cli_cli_header;
3465 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
3466 guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
3469 resources_size = ch->ch_resources.size;
3471 for (i = 0; i < table->rows; ++i) {
3472 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
3474 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
3475 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
3477 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
3478 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
3480 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
3481 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
3483 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
3484 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
3486 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3487 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3489 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
3490 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])));
3492 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
3493 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
3495 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
3496 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
3501 verify_nested_class_table (VerifyContext *ctx)
3503 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3504 guint32 data [MONO_NESTED_CLASS_SIZE];
3507 for (i = 0; i < table->rows; ++i) {
3508 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
3510 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3511 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
3512 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3513 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3514 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
3515 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3519 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
3521 verify_generic_param_table (VerifyContext *ctx)
3523 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
3524 guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
3525 int i, param_number = 0;
3527 for (i = 0; i < table->rows; ++i) {
3528 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
3530 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
3531 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
3533 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
3534 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
3536 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
3537 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
3539 token = data [MONO_GENERICPARAM_OWNER];
3541 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
3542 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
3544 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
3545 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
3547 if (token != last_token) {
3552 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
3553 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));
3560 verify_method_spec_table (VerifyContext *ctx)
3562 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3563 guint32 data [MONO_METHODSPEC_SIZE];
3566 for (i = 0; i < table->rows; ++i) {
3567 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3569 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3570 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
3572 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3573 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
3575 if (data [MONO_METHODSPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHODSPEC_SIGNATURE], 1))
3576 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid signature token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3581 verify_method_spec_table_full (VerifyContext *ctx)
3583 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3584 guint32 data [MONO_METHODSPEC_SIZE];
3587 for (i = 0; i < table->rows; ++i) {
3588 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3590 if (!is_valid_methodspec_blob (ctx, data [MONO_METHODSPEC_SIGNATURE]))
3591 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3596 verify_generic_param_constraint_table (VerifyContext *ctx)
3598 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
3599 guint32 data [MONO_GENPARCONSTRAINT_SIZE];
3602 for (i = 0; i < table->rows; ++i) {
3603 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
3605 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
3606 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_TABLE_GENERICPARAM]));
3608 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3609 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
3611 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3612 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
3619 const char *name_space;
3620 guint32 resolution_scope;
3624 typedef_hash (gconstpointer _key)
3626 const TypeDefUniqueId *key = _key;
3627 return g_str_hash (key->name) ^ g_str_hash (key->name_space) ^ key->resolution_scope; /*XXX better salt the int key*/
3631 typedef_equals (gconstpointer _a, gconstpointer _b)
3633 const TypeDefUniqueId *a = _a;
3634 const TypeDefUniqueId *b = _b;
3635 return !strcmp (a->name, b->name) && !strcmp (a->name_space, b->name_space) && a->resolution_scope == b->resolution_scope;
3639 verify_typedef_table_global_constraints (VerifyContext *ctx)
3642 guint32 data [MONO_TYPEDEF_SIZE];
3643 guint32 nested_data [MONO_NESTED_CLASS_SIZE];
3644 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
3645 MonoTableInfo *nested_table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3646 GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3648 for (i = 0; i < table->rows; ++i) {
3650 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3651 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
3653 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAME]);
3654 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAMESPACE]);
3655 type->resolution_scope = 0;
3657 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
3658 if (visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) {
3659 int res = search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1);
3660 g_assert (res >= 0);
3662 mono_metadata_decode_row (nested_table, res, nested_data, MONO_NESTED_CLASS_SIZE);
3663 type->resolution_scope = nested_data [MONO_NESTED_CLASS_ENCLOSING];
3666 if (g_hash_table_lookup (unique_types, type)) {
3667 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));
3668 g_hash_table_destroy (unique_types);
3672 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3675 g_hash_table_destroy (unique_types);
3679 verify_typeref_table_global_constraints (VerifyContext *ctx)
3682 guint32 data [MONO_TYPEREF_SIZE];
3683 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
3684 GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3686 for (i = 0; i < table->rows; ++i) {
3687 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3688 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
3690 type->resolution_scope = data [MONO_TYPEREF_SCOPE];
3691 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAME]);
3692 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAMESPACE]);
3694 if (g_hash_table_lookup (unique_types, type)) {
3695 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));
3696 g_hash_table_destroy (unique_types);
3700 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3703 g_hash_table_destroy (unique_types);
3707 verify_tables_data_global_constraints (VerifyContext *ctx)
3709 verify_typedef_table_global_constraints (ctx);
3713 verify_tables_data_global_constraints_full (VerifyContext *ctx)
3715 verify_typeref_table (ctx);
3716 verify_typeref_table_global_constraints (ctx);
3720 verify_tables_data (VerifyContext *ctx)
3722 OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
3723 guint32 size = 0, tables_offset;
3726 for (i = 0; i < 0x2D; ++i) {
3727 MonoTableInfo *table = &ctx->image->tables [i];
3729 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
3730 if (tmp_size < size) {
3738 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
3740 tables_offset = ctx->image->tables_base - ctx->data;
3741 if (!bounds_check_offset (&tables_area, tables_offset, size))
3742 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)));
3744 verify_module_table (ctx);
3746 /*Obfuscators love to place broken stuff in the typeref table
3747 verify_typeref_table (ctx);
3749 verify_typedef_table (ctx);
3751 verify_field_table (ctx);
3753 verify_method_table (ctx);
3755 verify_param_table (ctx);
3757 verify_interfaceimpl_table (ctx);
3759 verify_memberref_table (ctx);
3761 verify_constant_table (ctx);
3763 verify_cattr_table (ctx);
3765 verify_field_marshal_table (ctx);
3767 verify_decl_security_table (ctx);
3769 verify_class_layout_table (ctx);
3771 verify_field_layout_table (ctx);
3773 verify_standalonesig_table (ctx);
3775 verify_eventmap_table (ctx);
3777 verify_event_table (ctx);
3779 verify_propertymap_table (ctx);
3781 verify_property_table (ctx);
3783 verify_methodimpl_table (ctx);
3785 verify_moduleref_table (ctx);
3787 verify_typespec_table (ctx);
3789 verify_implmap_table (ctx);
3791 verify_fieldrva_table (ctx);
3793 verify_assembly_table (ctx);
3795 verify_assemblyref_table (ctx);
3797 verify_file_table (ctx);
3799 verify_exportedtype_table (ctx);
3801 verify_manifest_resource_table (ctx);
3803 verify_nested_class_table (ctx);
3805 verify_generic_param_table (ctx);
3807 verify_method_spec_table (ctx);
3809 verify_generic_param_constraint_table (ctx);
3811 verify_tables_data_global_constraints (ctx);
3815 init_verify_context (VerifyContext *ctx, MonoImage *image, gboolean report_error)
3817 memset (ctx, 0, sizeof (VerifyContext));
3819 ctx->report_error = report_error;
3820 ctx->report_warning = FALSE; //export this setting in the API
3822 ctx->size = image->raw_data_len;
3823 ctx->data = image->raw_data;
3827 cleanup_context (VerifyContext *ctx, GSList **error_list)
3829 g_free (ctx->sections);
3831 *error_list = ctx->errors;
3833 mono_free_verify_list (ctx->errors);
3838 cleanup_context_checked (VerifyContext *ctx, MonoError *error)
3840 g_free (ctx->sections);
3842 MonoVerifyInfo *info = ctx->errors->data;
3843 mono_error_set_bad_image (error, ctx->image, "%s", info->message);
3844 mono_free_verify_list (ctx->errors);
3850 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3854 if (!mono_verifier_is_enabled_for_image (image))
3857 init_verify_context (&ctx, image, error_list != NULL);
3858 ctx.stage = STAGE_PE;
3860 verify_msdos_header (&ctx);
3862 verify_pe_header (&ctx);
3864 verify_pe_optional_header (&ctx);
3866 load_section_table (&ctx);
3868 load_data_directories (&ctx);
3870 verify_import_table (&ctx);
3872 /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
3873 verify_resources_table (&ctx);
3876 return cleanup_context (&ctx, error_list);
3880 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3884 if (!mono_verifier_is_enabled_for_image (image))
3887 init_verify_context (&ctx, image, error_list != NULL);
3888 ctx.stage = STAGE_CLI;
3890 verify_cli_header (&ctx);
3892 verify_metadata_header (&ctx);
3894 verify_tables_schema (&ctx);
3897 return cleanup_context (&ctx, error_list);
3902 * Verifies basic table constraints such as global table invariants (sorting, field monotonicity, etc).
3903 * Other verification checks are meant to be done lazily by the runtime. Those include:
3904 * blob items (signatures, method headers, custom attributes, etc)
3905 * type semantics related
3907 * stuff that should not block other pieces from running such as bad types/methods/fields/etc.
3909 * The whole idea is that if this succeed the runtime is free to play around safely but any complex
3910 * operation still need more checking.
3913 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3917 if (!mono_verifier_is_enabled_for_image (image))
3920 init_verify_context (&ctx, image, error_list != NULL);
3921 ctx.stage = STAGE_TABLES;
3923 verify_tables_data (&ctx);
3925 return cleanup_context (&ctx, error_list);
3930 * Verifies all other constraints.
3933 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3937 if (!mono_verifier_is_enabled_for_image (image))
3940 init_verify_context (&ctx, image, error_list != NULL);
3941 ctx.stage = STAGE_TABLES;
3943 verify_typedef_table_full (&ctx);
3945 verify_field_table_full (&ctx);
3947 verify_method_table_full (&ctx);
3949 verify_memberref_table_full (&ctx);
3951 verify_cattr_table_full (&ctx);
3953 verify_field_marshal_table_full (&ctx);
3955 verify_decl_security_table_full (&ctx);
3957 verify_standalonesig_table_full (&ctx);
3959 verify_event_table_full (&ctx);
3961 verify_typespec_table_full (&ctx);
3963 verify_method_spec_table_full (&ctx);
3965 verify_tables_data_global_constraints_full (&ctx);
3968 return cleanup_context (&ctx, error_list);
3972 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
3976 if (!mono_verifier_is_enabled_for_image (image))
3979 init_verify_context (&ctx, image, error_list != NULL);
3980 ctx.stage = STAGE_TABLES;
3982 is_valid_field_signature (&ctx, offset);
3983 return cleanup_context (&ctx, error_list);
3987 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
3990 guint32 locals_token;
3992 if (!mono_verifier_is_enabled_for_image (image))
3995 init_verify_context (&ctx, image, error_list != NULL);
3996 ctx.stage = STAGE_TABLES;
3998 is_valid_method_header (&ctx, offset, &locals_token);
4000 guint32 sig_offset = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_STANDALONESIG], locals_token - 1, MONO_STAND_ALONE_SIGNATURE);
4001 is_valid_standalonesig_blob (&ctx, sig_offset);
4004 return cleanup_context (&ctx, error_list);
4008 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, MonoError *error)
4012 mono_error_init (error);
4014 if (!mono_verifier_is_enabled_for_image (image))
4017 init_verify_context (&ctx, image, TRUE);
4018 ctx.stage = STAGE_TABLES;
4020 is_valid_method_signature (&ctx, offset);
4021 /*XXX This returns a bad image exception, it might be the case that the right exception is method load.*/
4022 return cleanup_context_checked (&ctx, error);
4026 mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
4030 if (!mono_verifier_is_enabled_for_image (image))
4033 init_verify_context (&ctx, image, error_list != NULL);
4034 ctx.stage = STAGE_TABLES;
4036 is_valid_method_or_field_signature (&ctx, offset);
4037 return cleanup_context (&ctx, error_list);
4041 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
4045 if (!mono_verifier_is_enabled_for_image (image))
4048 init_verify_context (&ctx, image, error_list != NULL);
4049 ctx.stage = STAGE_TABLES;
4051 is_valid_standalonesig_blob (&ctx, offset);
4052 return cleanup_context (&ctx, error_list);
4056 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
4060 if (!mono_verifier_is_enabled_for_image (image))
4063 init_verify_context (&ctx, image, error_list != NULL);
4064 ctx.stage = STAGE_TABLES;
4067 is_valid_typespec_blob (&ctx, offset);
4068 return cleanup_context (&ctx, error_list);
4072 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
4076 if (!mono_verifier_is_enabled_for_image (image))
4079 init_verify_context (&ctx, image, error_list != NULL);
4080 ctx.stage = STAGE_TABLES;
4082 is_valid_methodspec_blob (&ctx, offset);
4083 return cleanup_context (&ctx, error_list);
4087 verify_user_string (VerifyContext *ctx, guint32 offset)
4089 OffsetAndSize heap_us = get_metadata_stream (ctx, &ctx->image->heap_us);
4090 guint32 entry_size, bytes;
4092 if (heap_us.size < offset)
4093 ADD_ERROR (ctx, g_strdup ("User string offset beyond heap_us size"));
4095 if (!decode_value (ctx->data + offset + heap_us.offset, heap_us.size - heap_us.offset, &entry_size, &bytes))
4096 ADD_ERROR (ctx, g_strdup ("Could not decode user string blob size"));
4098 if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
4099 ADD_ERROR (ctx, g_strdup ("User string size overflow"));
4101 entry_size += bytes;
4103 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, heap_us.size))
4104 ADD_ERROR (ctx, g_strdup ("User string oveflow heap_us"));
4108 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
4112 if (!mono_verifier_is_enabled_for_image (image))
4115 init_verify_context (&ctx, image, error_list != NULL);
4116 ctx.stage = STAGE_TABLES;
4118 verify_user_string (&ctx, offset);
4120 return cleanup_context (&ctx, error_list);
4124 mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, GSList **error_list)
4128 if (!mono_verifier_is_enabled_for_image (image))
4131 init_verify_context (&ctx, image, error_list != NULL);
4132 ctx.stage = STAGE_TABLES;
4134 is_valid_cattr_blob (&ctx, offset);
4136 return cleanup_context (&ctx, error_list);
4140 mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, GSList **error_list)
4144 if (!mono_verifier_is_enabled_for_image (image))
4147 init_verify_context (&ctx, image, error_list != NULL);
4148 ctx.stage = STAGE_TABLES;
4150 is_valid_cattr_content (&ctx, ctor, (const char*)data, size);
4152 return cleanup_context (&ctx, error_list);
4156 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
4158 MonoMethodSignature *original_sig;
4159 if (!mono_verifier_is_enabled_for_image (image))
4162 original_sig = mono_method_signature (method);
4163 if (original_sig->call_convention == MONO_CALL_VARARG) {
4164 if (original_sig->hasthis != signature->hasthis)
4166 if (original_sig->call_convention != signature->call_convention)
4168 if (original_sig->explicit_this != signature->explicit_this)
4170 if (original_sig->call_convention != signature->call_convention)
4172 if (original_sig->pinvoke != signature->pinvoke)
4174 if (original_sig->sentinelpos != signature->sentinelpos)
4176 } else if (!mono_metadata_signature_equal (signature, original_sig)) {
4184 mono_verifier_verify_typeref_row (MonoImage *image, guint32 row, MonoError *error)
4186 MonoTableInfo *table = &image->tables [MONO_TABLE_TYPEREF];
4187 guint32 data [MONO_TYPEREF_SIZE];
4189 mono_error_init (error);
4191 if (!mono_verifier_is_enabled_for_image (image))
4194 if (row >= table->rows) {
4195 mono_error_set_bad_image (error, image, "Invalid typeref row %d - table has %d rows", row, table->rows);
4199 mono_metadata_decode_row (table, row, data, MONO_TYPEREF_SIZE);
4200 if (!is_valid_coded_index_with_image (image, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE])) {
4201 mono_error_set_bad_image (error, image, "Invalid typeref row %d coded index 0x%08x", row, data [MONO_TYPEREF_SCOPE]);
4205 if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE])) {
4206 mono_error_set_bad_image (error, image, "The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", row);
4210 if (!data [MONO_TYPEREF_NAME] || !is_valid_string_full_with_image (image, data [MONO_TYPEREF_NAME], FALSE)) {
4211 mono_error_set_bad_image (error, image, "Invalid typeref row %d name token 0x%08x", row, data [MONO_TYPEREF_NAME]);
4215 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_string_full_with_image (image, data [MONO_TYPEREF_NAMESPACE], FALSE)) {
4216 mono_error_set_bad_image (error, image, "Invalid typeref row %d namespace token 0x%08x", row, data [MONO_TYPEREF_NAMESPACE]);
4223 /*Perform additional verification including metadata ones*/
4225 mono_verifier_verify_methodimpl_row (MonoImage *image, guint32 row, MonoError *error)
4227 MonoMethod *declaration, *body;
4228 MonoMethodSignature *body_sig, *decl_sig;
4229 MonoTableInfo *table = &image->tables [MONO_TABLE_METHODIMPL];
4230 guint32 data [MONO_METHODIMPL_SIZE];
4232 mono_error_init (error);
4234 if (!mono_verifier_is_enabled_for_image (image))
4237 if (row >= table->rows) {
4238 mono_error_set_bad_image (error, image, "Invalid methodimpl row %d - table has %d rows", row, table->rows);
4242 mono_metadata_decode_row (table, row, data, MONO_METHODIMPL_SIZE);
4244 body = method_from_method_def_or_ref (image, data [MONO_METHODIMPL_BODY], NULL);
4245 if (mono_loader_get_last_error ()) {
4246 mono_loader_clear_error ();
4247 mono_error_set_bad_image (error, image, "Invalid methodimpl body for row %x", row);
4251 declaration = method_from_method_def_or_ref (image, data [MONO_METHODIMPL_DECLARATION], NULL);
4252 if (mono_loader_get_last_error ()) {
4253 mono_loader_clear_error ();
4254 mono_error_set_bad_image (error, image, "Invalid methodimpl declaration for row %x", row);
4259 mono_class_setup_supertypes (class);
4260 if (!mono_class_has_parent (class, body->klass)) {
4261 mono_error_set_bad_image (error, image, "Invalid methodimpl body doesn't belong to parent for row %x", row);
4265 if (!(body_sig = mono_method_signature_checked (body, error))) {
4269 if (!(decl_sig = mono_method_signature_checked (declaration, error))) {
4273 if (!mono_verifier_is_signature_compatible (decl_sig, body_sig)) {
4274 mono_error_set_bad_image (error, image, "Invalid methodimpl body signature not compatible with declaration row %x", row);
4283 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
4289 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
4295 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
4301 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
4307 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4313 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
4319 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, MonoError *error)
4321 mono_error_init (error);
4326 mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
4332 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
4338 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
4344 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
4350 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
4356 mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, GSList **error_list)
4362 mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, GSList **error_list)
4368 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
4375 mono_verifier_verify_typeref_row (MonoImage *image, guint32 row, MonoError *error)
4377 mono_error_init (error);
4382 mono_verifier_verify_methodimpl_row (MonoImage *image, guint32 row, MonoError *error)
4384 mono_error_init (error);
4388 #endif /* DISABLE_VERIFIER */