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)
8 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
10 #include <mono/metadata/object-internals.h>
11 #include <mono/metadata/verify.h>
12 #include <mono/metadata/verify-internals.h>
13 #include <mono/metadata/opcodes.h>
14 #include <mono/metadata/tabledefs.h>
15 #include <mono/metadata/reflection.h>
16 #include <mono/metadata/debug-helpers.h>
17 #include <mono/metadata/mono-endian.h>
18 #include <mono/metadata/metadata.h>
19 #include <mono/metadata/metadata-internals.h>
20 #include <mono/metadata/class-internals.h>
21 #include <mono/metadata/tokentype.h>
22 #include <mono/metadata/security-manager.h>
23 #include <mono/metadata/security-core-clr.h>
24 #include <mono/metadata/cil-coff.h>
25 #include <mono/metadata/attrdefs.h>
26 #include <mono/utils/strenc.h>
27 #include <mono/utils/mono-error-internals.h>
28 #include <mono/utils/bsearch.h>
33 #ifndef DISABLE_VERIFIER
35 TODO add fail fast mode
36 TODO add PE32+ support
37 TODO verify the entry point RVA and content.
38 TODO load_section_table and load_data_directories must take PE32+ into account
39 TODO add section relocation support
40 TODO verify the relocation table, since we really don't use, no need so far.
41 TODO do full PECOFF resources verification
42 TODO verify in the CLI header entry point and resources
43 TODO implement null token typeref validation
44 TODO verify table wide invariants for typedef (sorting and uniqueness)
45 TODO implement proper authenticode data directory validation
46 TODO verify properties that require multiple tables to be valid
47 FIXME use subtraction based bounds checking to avoid overflows
48 FIXME get rid of metadata_streams and other fields from VerifyContext
51 #ifdef MONO_VERIFIER_DEBUG
52 #define VERIFIER_DEBUG(code) do { code; } while (0)
54 #define VERIFIER_DEBUG(code)
57 #define INVALID_OFFSET ((guint32)-1)
58 #define INVALID_ADDRESS 0xffffffff
68 RESOURCE_TABLE_IDX = 2,
69 CERTIFICATE_TABLE_IDX = 4,
70 RELOCATION_TABLE_IDX = 5,
84 #define INVALID_TABLE (0xFF)
85 /*format: number of bits, number of tables, tables{n. tables} */
86 const static unsigned char coded_index_desc[] = {
87 #define TYPEDEF_OR_REF_DESC (0)
94 #define HAS_CONSTANT_DESC (TYPEDEF_OR_REF_DESC + 5)
101 #define HAS_CATTR_DESC (HAS_CONSTANT_DESC + 5)
109 MONO_TABLE_INTERFACEIMPL,
110 MONO_TABLE_MEMBERREF,
112 MONO_TABLE_DECLSECURITY,
115 MONO_TABLE_STANDALONESIG,
116 MONO_TABLE_MODULEREF,
119 MONO_TABLE_ASSEMBLYREF,
121 MONO_TABLE_EXPORTEDTYPE,
122 MONO_TABLE_MANIFESTRESOURCE,
123 MONO_TABLE_GENERICPARAM,
125 #define HAS_FIELD_MARSHAL_DESC (HAS_CATTR_DESC + 22)
131 #define HAS_DECL_SECURITY_DESC (HAS_FIELD_MARSHAL_DESC + 4)
138 #define MEMBERREF_PARENT_DESC (HAS_DECL_SECURITY_DESC + 5)
143 MONO_TABLE_MODULEREF,
147 #define HAS_SEMANTICS_DESC (MEMBERREF_PARENT_DESC + 7)
153 #define METHODDEF_OR_REF_DESC (HAS_SEMANTICS_DESC + 4)
157 MONO_TABLE_MEMBERREF,
159 #define MEMBER_FORWARDED_DESC (METHODDEF_OR_REF_DESC + 4)
165 #define IMPLEMENTATION_DESC (MEMBER_FORWARDED_DESC + 4)
169 MONO_TABLE_ASSEMBLYREF,
170 MONO_TABLE_EXPORTEDTYPE,
172 #define CATTR_TYPE_DESC (IMPLEMENTATION_DESC + 5)
178 MONO_TABLE_MEMBERREF,
181 #define RES_SCOPE_DESC (CATTR_TYPE_DESC + 7)
185 MONO_TABLE_MODULEREF,
186 MONO_TABLE_ASSEMBLYREF,
189 #define TYPE_OR_METHODDEF_DESC (RES_SCOPE_DESC + 6)
199 guint32 translated_offset;
211 guint32 rellocationsRVA;
212 guint16 numberOfRelocations;
227 gboolean report_error;
228 gboolean report_warning;
231 DataDirectory data_directories [16];
232 guint32 section_count;
233 SectionHeader *sections;
235 OffsetAndSize metadata_streams [5]; //offset from begin of the image
238 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception) \
240 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
241 vinfo->info.status = __status; \
242 vinfo->info.message = ( __msg); \
243 vinfo->exception_type = (__exception); \
244 (__ctx)->errors = g_slist_prepend ((__ctx)->errors, vinfo); \
247 #define ADD_WARNING(__ctx, __msg) \
249 if ((__ctx)->report_warning) { \
250 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_WARNING, MONO_EXCEPTION_INVALID_PROGRAM); \
251 (__ctx)->valid = 0; \
256 #define ADD_ERROR_NO_RETURN(__ctx, __msg) \
258 if ((__ctx)->report_error) \
259 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
260 (__ctx)->valid = 0; \
263 #define ADD_ERROR(__ctx, __msg) \
265 if ((__ctx)->report_error) \
266 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
267 (__ctx)->valid = 0; \
271 #define FAIL(__ctx, __msg) \
273 if ((__ctx)->report_error) \
274 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
275 (__ctx)->valid = 0; \
279 #define CHECK_STATE() do { if (!ctx.valid) goto cleanup; } while (0)
281 #define CHECK_ERROR() do { if (!ctx->valid) return; } while (0)
283 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
284 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
286 #if SIZEOF_VOID_P == 4
287 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
289 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
292 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
293 #define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
296 dword_align (const char *ptr)
298 #if SIZEOF_VOID_P == 8
299 return (const char *) (((guint64) (ptr + 3)) & ~3);
301 return (const char *) (((guint32) (ptr + 3)) & ~3);
306 add_from_mono_error (VerifyContext *ctx, MonoError *error)
308 if (mono_error_ok (error))
311 ADD_ERROR (ctx, g_strdup (mono_error_get_message (error)));
312 mono_error_cleanup (error);
316 pe_signature_offset (VerifyContext *ctx)
318 return read32 (ctx->data + 0x3c);
322 pe_header_offset (VerifyContext *ctx)
324 return read32 (ctx->data + 0x3c) + 4;
328 bounds_check_virtual_address (VerifyContext *ctx, guint32 rva, guint32 size)
332 if (rva + size < rva) //overflow
335 if (ctx->stage > STAGE_PE) {
336 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)ctx->image->image_info;
337 const int top = iinfo->cli_section_count;
338 MonoSectionTable *tables = iinfo->cli_section_tables;
341 for (i = 0; i < top; i++) {
342 guint32 base = tables->st_virtual_address;
343 guint32 end = base + tables->st_raw_data_size;
345 if (rva >= base && rva + size <= end)
348 /*if ((addr >= tables->st_virtual_address) &&
349 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
351 return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
361 for (i = 0; i < ctx->section_count; ++i) {
362 guint32 base = ctx->sections [i].baseRVA;
363 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
364 if (rva >= base && rva + size <= end)
371 bounds_check_datadir (DataDirectory *dir, guint32 offset, guint32 size)
373 if (dir->translated_offset > offset)
375 if (dir->size < size)
377 return offset + size <= dir->translated_offset + dir->size;
381 bounds_check_offset (OffsetAndSize *off, guint32 offset, guint32 size)
383 if (off->offset > offset)
386 if (off->size < size)
389 return offset + size <= off->offset + off->size;
393 translate_rva (VerifyContext *ctx, guint32 rva)
397 if (ctx->stage > STAGE_PE)
398 return mono_cli_rva_image_map (ctx->image, rva);
403 for (i = 0; i < ctx->section_count; ++i) {
404 guint32 base = ctx->sections [i].baseRVA;
405 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
406 if (rva >= base && rva <= end) {
407 guint32 res = (rva - base) + ctx->sections [i].baseOffset;
409 return res >= ctx->size ? INVALID_OFFSET : res;
413 return INVALID_OFFSET;
417 verify_msdos_header (VerifyContext *ctx)
421 ADD_ERROR (ctx, g_strdup ("Not enough space for the MS-DOS header"));
422 if (ctx->data [0] != 0x4d || ctx->data [1] != 0x5a)
423 ADD_ERROR (ctx, g_strdup ("Invalid MS-DOS watermark"));
424 lfanew = pe_signature_offset (ctx);
425 if (lfanew > ctx->size - 4)
426 ADD_ERROR (ctx, g_strdup ("MS-DOS lfanew offset points to outside of the file"));
430 verify_pe_header (VerifyContext *ctx)
432 guint32 offset = pe_signature_offset (ctx);
433 const char *pe_header = ctx->data + offset;
434 if (pe_header [0] != 'P' || pe_header [1] != 'E' ||pe_header [2] != 0 ||pe_header [3] != 0)
435 ADD_ERROR (ctx, g_strdup ("Invalid PE header watermark"));
439 if (offset > ctx->size - 20)
440 ADD_ERROR (ctx, g_strdup ("File with truncated pe header"));
441 if (read16 (pe_header) != 0x14c)
442 ADD_ERROR (ctx, g_strdup ("Invalid PE header Machine value"));
446 verify_pe_optional_header (VerifyContext *ctx)
448 guint32 offset = pe_header_offset (ctx);
449 guint32 header_size, file_alignment;
450 const char *pe_header = ctx->data + offset;
451 const char *pe_optional_header = pe_header + 20;
453 header_size = read16 (pe_header + 16);
456 if (header_size < 2) /*must be at least 2 or we won't be able to read magic*/
457 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
459 if (offset > ctx->size - header_size || header_size > ctx->size)
460 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
462 if (read16 (pe_optional_header) == 0x10b) {
463 if (header_size != 224)
464 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header size %d", header_size));
466 /* LAMESPEC MS plays around this value and ignore it during validation
467 if (read32 (pe_optional_header + 28) != 0x400000)
468 ADD_ERROR (ctx, g_strdup_printf ("Invalid Image base %x", read32 (pe_optional_header + 28)));*/
469 if (read32 (pe_optional_header + 32) != 0x2000)
470 ADD_ERROR (ctx, g_strdup_printf ("Invalid Section Aligmnent %x", read32 (pe_optional_header + 32)));
471 file_alignment = read32 (pe_optional_header + 36);
472 if (file_alignment != 0x200 && file_alignment != 0x1000)
473 ADD_ERROR (ctx, g_strdup_printf ("Invalid file Aligmnent %x", file_alignment));
474 /* All the junk in the middle is irrelevant, specially for mono. */
475 if (read32 (pe_optional_header + 92) > 0x10)
476 ADD_ERROR (ctx, g_strdup_printf ("Too many data directories %x", read32 (pe_optional_header + 92)));
478 if (read16 (pe_optional_header) == 0x20B)
479 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle PE32+"));
481 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header magic %d", read16 (pe_optional_header)));
486 load_section_table (VerifyContext *ctx)
489 SectionHeader *sections;
490 guint32 offset = pe_header_offset (ctx);
491 const char *ptr = ctx->data + offset;
492 guint16 num_sections = ctx->section_count = read16 (ptr + 2);
494 offset += 244;/*FIXME, this constant is different under PE32+*/
497 if (num_sections * 40 > ctx->size - offset)
498 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
500 sections = ctx->sections = g_new0 (SectionHeader, num_sections);
501 for (i = 0; i < num_sections; ++i) {
502 sections [i].size = read32 (ptr + 8);
503 sections [i].baseRVA = read32 (ptr + 12);
504 sections [i].baseOffset = read32 (ptr + 20);
505 sections [i].rellocationsRVA = read32 (ptr + 24);
506 sections [i].numberOfRelocations = read16 (ptr + 32);
510 ptr = ctx->data + offset; /*reset it to the beggining*/
511 for (i = 0; i < num_sections; ++i) {
512 guint32 raw_size, flags;
513 if (sections [i].baseOffset == 0)
514 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with intialized data only"));
515 if (sections [i].baseOffset >= ctx->size)
516 ADD_ERROR (ctx, g_strdup_printf ("Invalid PointerToRawData %x points beyond EOF", sections [i].baseOffset));
517 if (sections [i].size > ctx->size - sections [i].baseOffset)
518 ADD_ERROR (ctx, g_strdup ("Invalid VirtualSize points beyond EOF"));
520 raw_size = read32 (ptr + 16);
521 if (raw_size < sections [i].size)
522 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with SizeOfRawData < VirtualSize"));
524 if (raw_size > ctx->size - sections [i].baseOffset)
525 ADD_ERROR (ctx, g_strdup_printf ("Invalid SizeOfRawData %x points beyond EOF", raw_size));
527 if (sections [i].rellocationsRVA || sections [i].numberOfRelocations)
528 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't handle section relocation"));
530 flags = read32 (ptr + 36);
531 /*TODO 0xFE0000E0 is all flags from cil-coff.h OR'd. Make it a less magical number*/
532 if (flags == 0 || (flags & ~0xFE0000E0) != 0)
533 ADD_ERROR (ctx, g_strdup_printf ("Invalid section flags %x", flags));
540 is_valid_data_directory (int i)
542 /*LAMESPEC 4 == certificate 6 == debug, MS uses both*/
543 return i == 1 || i == 2 || i == 5 || i == 12 || i == 14 || i == 4 || i == 6;
547 load_data_directories (VerifyContext *ctx)
549 guint32 offset = pe_header_offset (ctx) + 116; /*FIXME, this constant is different under PE32+*/
550 const char *ptr = ctx->data + offset;
553 for (i = 0; i < 16; ++i) {
554 guint32 rva = read32 (ptr);
555 guint32 size = read32 (ptr + 4);
557 /*LAMESPEC the authenticode data directory format is different. We don't support CAS, so lets ignore for now.*/
558 if (i == CERTIFICATE_TABLE_IDX) {
562 if ((rva != 0 || size != 0) && !is_valid_data_directory (i))
563 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d", i));
565 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
566 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d rva/size pair %x/%x", i, rva, size));
568 ctx->data_directories [i].rva = rva;
569 ctx->data_directories [i].size = size;
570 ctx->data_directories [i].translated_offset = translate_rva (ctx, rva);
576 #define SIZE_OF_MSCOREE (sizeof ("mscoree.dll"))
578 #define SIZE_OF_CORMAIN (sizeof ("_CorExeMain"))
581 verify_hint_name_table (VerifyContext *ctx, guint32 import_rva, const char *table_name)
584 guint32 hint_table_rva;
586 import_rva = translate_rva (ctx, import_rva);
587 g_assert (import_rva != INVALID_OFFSET);
589 hint_table_rva = read32 (ctx->data + import_rva);
590 if (!bounds_check_virtual_address (ctx, hint_table_rva, SIZE_OF_CORMAIN + 2))
591 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint/Name rva %d for %s", hint_table_rva, table_name));
593 hint_table_rva = translate_rva (ctx, hint_table_rva);
594 g_assert (hint_table_rva != INVALID_OFFSET);
595 ptr = ctx->data + hint_table_rva + 2;
597 if (memcmp ("_CorExeMain", ptr, SIZE_OF_CORMAIN) && memcmp ("_CorDllMain", ptr, SIZE_OF_CORMAIN)) {
598 char name[SIZE_OF_CORMAIN];
599 memcpy (name, ptr, SIZE_OF_CORMAIN);
600 name [SIZE_OF_CORMAIN - 1] = 0;
601 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint / Name: '%s'", name));
606 verify_import_table (VerifyContext *ctx)
608 DataDirectory it = ctx->data_directories [IMPORT_TABLE_IDX];
609 guint32 offset = it.translated_offset;
610 const char *ptr = ctx->data + offset;
611 guint32 name_rva, ilt_rva, iat_rva;
613 g_assert (offset != INVALID_OFFSET);
616 ADD_ERROR (ctx, g_strdup_printf ("Import table size %d is smaller than 40", it.size));
618 ilt_rva = read32 (ptr);
619 if (ilt_rva && !bounds_check_virtual_address (ctx, ilt_rva, 8))
620 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Lookup Table rva %x", ilt_rva));
622 name_rva = read32 (ptr + 12);
623 if (name_rva && !bounds_check_virtual_address (ctx, name_rva, SIZE_OF_MSCOREE))
624 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name rva %x", name_rva));
626 iat_rva = read32 (ptr + 16);
628 if (!bounds_check_virtual_address (ctx, iat_rva, 8))
629 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Address Table rva %x", iat_rva));
631 if (iat_rva != ctx->data_directories [IAT_IDX].rva)
632 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));
636 name_rva = translate_rva (ctx, name_rva);
637 g_assert (name_rva != INVALID_OFFSET);
638 ptr = ctx->data + name_rva;
640 if (memcmp ("mscoree.dll", ptr, SIZE_OF_MSCOREE)) {
641 char name[SIZE_OF_MSCOREE];
642 memcpy (name, ptr, SIZE_OF_MSCOREE);
643 name [SIZE_OF_MSCOREE - 1] = 0;
644 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name: '%s'", name));
649 verify_hint_name_table (ctx, ilt_rva, "Import Lookup Table");
654 verify_hint_name_table (ctx, iat_rva, "Import Address Table");
658 verify_resources_table (VerifyContext *ctx)
660 DataDirectory it = ctx->data_directories [RESOURCE_TABLE_IDX];
662 guint16 named_entries, id_entries;
669 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));
671 offset = it.translated_offset;
672 ptr = ctx->data + offset;
674 g_assert (offset != INVALID_OFFSET);
676 named_entries = read16 (ptr + 12);
677 id_entries = read16 (ptr + 14);
679 if ((named_entries + id_entries) * 8 + 16 > it.size)
680 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));
682 /* XXX at least one unmanaged resource is added due to a call to AssemblyBuilder::DefineVersionInfoResource ()
683 if (named_entries || id_entries)
684 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support full verification of PECOFF resources"));
688 /*----------nothing from here on can use data_directory---*/
691 get_data_dir (VerifyContext *ctx, int idx)
693 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)ctx->image->image_info;
694 MonoPEDirEntry *entry= &iinfo->cli_header.datadir.pe_export_table;
698 res.rva = entry->rva;
699 res.size = entry->size;
700 res.translated_offset = translate_rva (ctx, res.rva);
705 verify_cli_header (VerifyContext *ctx)
707 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
713 ADD_ERROR (ctx, g_strdup_printf ("CLI header missing"));
716 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size in data directory %d must be 72", it.size));
718 offset = it.translated_offset;
719 ptr = ctx->data + offset;
721 g_assert (offset != INVALID_OFFSET);
723 if (read16 (ptr) != 72)
724 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size %d must be 72", read16 (ptr)));
726 if (!bounds_check_virtual_address (ctx, read32 (ptr + 8), read32 (ptr + 12)))
727 ADD_ERROR (ctx, g_strdup_printf ("Invalid medatata section rva/size pair %x/%x", read32 (ptr + 8), read32 (ptr + 12)));
730 if (!read32 (ptr + 8) || !read32 (ptr + 12))
731 ADD_ERROR (ctx, g_strdup_printf ("Missing medatata section in the CLI header"));
733 if ((read32 (ptr + 16) & ~0x0003000B) != 0)
734 ADD_ERROR (ctx, g_strdup_printf ("Invalid CLI header flags"));
737 for (i = 0; i < 6; ++i) {
738 guint32 rva = read32 (ptr);
739 guint32 size = read32 (ptr + 4);
741 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
742 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli section %i rva/size pair %x/%x", i, rva, size));
747 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't support cli header section %d", i));
752 pad4 (guint32 offset)
754 if (offset & 0x3) //pad to the next 4 byte boundary
755 offset = (offset & ~0x3) + 4;
760 verify_metadata_header (VerifyContext *ctx)
763 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
764 guint32 offset, section_count;
767 offset = it.translated_offset;
768 ptr = ctx->data + offset;
769 g_assert (offset != INVALID_OFFSET);
771 //build a directory entry for the metadata root
773 it.rva = read32 (ptr);
775 it.size = read32 (ptr);
776 it.translated_offset = offset = translate_rva (ctx, it.rva);
778 ptr = ctx->data + offset;
779 g_assert (offset != INVALID_OFFSET);
782 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small %d (at least 20 bytes required for initial decoding)", it.size));
784 if (read32 (ptr) != 0x424A5342)
785 ADD_ERROR (ctx, g_strdup_printf ("Invalid metadata signature, expected 0x424A5342 but got %08x", read32 (ptr)));
787 offset = pad4 (offset + 16 + read32 (ptr + 12));
789 if (!bounds_check_datadir (&it, offset, 4))
790 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));
792 ptr = ctx->data + offset; //move to streams header
794 section_count = read16 (ptr + 2);
795 if (section_count < 2)
796 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section must have at least 2 streams (#~ and #GUID)"));
801 for (i = 0; i < section_count; ++i) {
802 guint32 stream_off, stream_size;
803 int string_size, stream_idx;
805 if (!bounds_check_datadir (&it, offset, 8))
806 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));
808 stream_off = it.translated_offset + read32 (ptr);
809 stream_size = read32 (ptr + 4);
811 if (!bounds_check_datadir (&it, stream_off, stream_size))
812 ADD_ERROR (ctx, g_strdup_printf ("Invalid stream header %d offset/size pair %x/%x", 0, stream_off, stream_size));
817 for (string_size = 0; string_size < 32; ++string_size) {
818 if (!bounds_check_datadir (&it, offset++, 1))
819 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small to decode stream header %d name", i));
820 if (!ptr [string_size])
824 if (ptr [string_size])
825 ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d name larger than 32 bytes", i));
827 if (!strncmp ("#Strings", ptr, 9))
828 stream_idx = STRINGS_STREAM;
829 else if (!strncmp ("#US", ptr, 4))
830 stream_idx = USER_STRINGS_STREAM;
831 else if (!strncmp ("#Blob", ptr, 6))
832 stream_idx = BLOB_STREAM;
833 else if (!strncmp ("#GUID", ptr, 6))
834 stream_idx = GUID_STREAM;
835 else if (!strncmp ("#~", ptr, 3))
836 stream_idx = TILDE_STREAM;
838 ADD_WARNING (ctx, g_strdup_printf ("Metadata stream header %d invalid name %s", i, ptr));
839 offset = pad4 (offset);
840 ptr = ctx->data + offset;
844 if (ctx->metadata_streams [stream_idx].offset != 0)
845 ADD_ERROR (ctx, g_strdup_printf ("Duplicated metadata stream header %s", ptr));
847 ctx->metadata_streams [stream_idx].offset = stream_off;
848 ctx->metadata_streams [stream_idx].size = stream_size;
850 offset = pad4 (offset);
851 ptr = ctx->data + offset;
854 if (!ctx->metadata_streams [TILDE_STREAM].size)
855 ADD_ERROR (ctx, g_strdup_printf ("Metadata #~ stream missing"));
856 if (!ctx->metadata_streams [GUID_STREAM].size)
857 ADD_ERROR (ctx, g_strdup_printf ("Metadata guid stream missing"));
861 verify_tables_schema (VerifyContext *ctx)
863 OffsetAndSize tables_area = ctx->metadata_streams [TILDE_STREAM];
864 unsigned offset = tables_area.offset;
865 const char *ptr = ctx->data + offset;
866 guint64 valid_tables;
870 if (tables_area.size < 24)
871 ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for initial decoding (requires 24 bytes)", tables_area.size));
873 if (ptr [4] != 2 && ptr [4] != 1)
874 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata major version %d, expected 2", ptr [4]));
876 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata minor version %d, expected 0", ptr [5]));
878 if ((ptr [6] & ~0x7) != 0)
879 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]));
881 valid_tables = read64 (ptr + 8);
883 for (i = 0; i < 64; ++i) {
884 if (!(valid_tables & ((guint64)1 << i)))
887 /*MS Extensions: 0x3 0x5 0x7 0x13 0x16
888 Unused: 0x1E 0x1F 0x2D-0x3F
889 We don't care about the MS extensions.*/
890 if (i == 0x3 || i == 0x5 || i == 0x7 || i == 0x13 || i == 0x16)
891 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support MS specific table %x", i));
892 if (i == 0x1E || i == 0x1F || i >= 0x2D)
893 ADD_ERROR (ctx, g_strdup_printf ("Invalid table %x", i));
897 if (tables_area.size < 24 + count * 4)
898 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));
901 for (i = 0; i < 64; ++i) {
902 if (valid_tables & ((guint64)1 << i)) {
903 guint32 row_count = read32 (ptr);
904 if (row_count > (1 << 24) - 1)
905 ADD_ERROR (ctx, g_strdup_printf ("Invalid Table %d row count: %d. Mono only supports 16777215 rows", i, row_count));
911 /*----------nothing from here on can use data_directory or metadata_streams ---*/
914 get_col_offset (VerifyContext *ctx, int table, int column)
916 guint32 bitfield = ctx->image->tables [table].size_bitfield;
920 offset += mono_metadata_table_size (bitfield, column);
926 get_col_size (VerifyContext *ctx, int table, int column)
928 return mono_metadata_table_size (ctx->image->tables [table].size_bitfield, column);
932 get_metadata_stream (VerifyContext *ctx, MonoStreamHeader *header)
935 res.offset = header->data - ctx->data;
936 res.size = header->size;
942 is_valid_string_full_with_image (MonoImage *image, guint32 offset, gboolean allow_empty)
944 guint32 heap_offset = (char*)image->heap_strings.data - image->raw_data;
945 guint32 heap_size = image->heap_strings.size;
948 const char *data = image->raw_data + heap_offset;
950 if (offset >= heap_size)
952 if (CHECK_ADDP_OVERFLOW_UN (data, offset))
955 if (!mono_utf8_validate_and_len_with_bounds (data + offset, heap_size - offset, &length, NULL))
957 return allow_empty || length > 0;
962 is_valid_string_full (VerifyContext *ctx, guint32 offset, gboolean allow_empty)
964 return is_valid_string_full_with_image (ctx->image, offset, allow_empty);
968 is_valid_string (VerifyContext *ctx, guint32 offset)
970 return is_valid_string_full (ctx, offset, TRUE);
974 is_valid_non_empty_string (VerifyContext *ctx, guint32 offset)
976 return is_valid_string_full (ctx, offset, FALSE);
980 is_valid_guid (VerifyContext *ctx, guint32 offset)
982 OffsetAndSize guids = get_metadata_stream (ctx, &ctx->image->heap_guid);
983 return guids.size >= 8 && guids.size - 8 >= offset;
987 get_coded_index_token (int token_kind, guint32 coded_token)
989 guint32 bits = coded_index_desc [token_kind];
990 return coded_token >> bits;
994 get_coded_index_table (int kind, guint32 coded_token)
996 guint32 idx, bits = coded_index_desc [kind];
998 idx = coded_token & ((1 << bits) - 1);
999 return coded_index_desc [kind + idx];
1003 make_coded_token (int kind, guint32 table, guint32 table_idx)
1005 guint32 bits = coded_index_desc [kind++];
1006 guint32 tables = coded_index_desc [kind++];
1008 for (i = 0; i < tables; ++i) {
1009 if (coded_index_desc [kind++] == table)
1010 return ((table_idx + 1) << bits) | i;
1012 g_assert_not_reached ();
1017 is_valid_coded_index_with_image (MonoImage *image, int token_kind, guint32 coded_token)
1019 guint32 bits = coded_index_desc [token_kind++];
1020 guint32 table_count = coded_index_desc [token_kind++];
1021 guint32 table = coded_token & ((1 << bits) - 1);
1022 guint32 token = coded_token >> bits;
1024 if (table >= table_count)
1027 /*token_kind points to the first table idx*/
1028 table = coded_index_desc [token_kind + table];
1030 if (table == INVALID_TABLE)
1032 return token <= image->tables [table].rows;
1036 is_valid_coded_index (VerifyContext *ctx, int token_kind, guint32 coded_token)
1038 return is_valid_coded_index_with_image (ctx->image, token_kind, coded_token);
1045 MonoTableInfo *table;
1049 token_locator (const void *a, const void *b)
1051 RowLocator *loc = (RowLocator *)a;
1052 unsigned const char *row = (unsigned const char *)b;
1053 guint32 token = loc->col_size == 2 ? read16 (row + loc->col_offset) : read32 (row + loc->col_offset);
1055 VERIFIER_DEBUG ( printf ("\tfound token %x at idx %d\n", token, ((const char*)row - loc->table->base) / loc->table->row_size) );
1056 return (int)loc->token - (int)token;
1060 search_sorted_table (VerifyContext *ctx, int table, int column, guint32 coded_token)
1062 MonoTableInfo *tinfo = &ctx->image->tables [table];
1064 const char *res, *base;
1065 locator.token = coded_token;
1066 locator.col_offset = get_col_offset (ctx, table, column);
1067 locator.col_size = get_col_size (ctx, table, column);
1068 locator.table = tinfo;
1072 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) );
1073 res = (const char *)mono_binary_search (&locator, base, tinfo->rows, tinfo->row_size, token_locator);
1077 return (res - base) / tinfo->row_size;
1080 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1082 get_string_ptr (VerifyContext *ctx, guint offset)
1084 return ctx->image->heap_strings.data + offset;
1087 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1089 string_cmp (VerifyContext *ctx, const char *str, guint offset)
1092 return strcmp (str, "");
1094 return strcmp (str, get_string_ptr (ctx, offset));
1098 mono_verifier_is_corlib (MonoImage *image)
1100 gboolean trusted_location = !mono_security_core_clr_enabled () ?
1101 TRUE : mono_security_core_clr_is_platform_image (image);
1103 return trusted_location && image->module_name && !strcmp ("mscorlib.dll", image->module_name);
1107 typedef_is_system_object (VerifyContext *ctx, guint32 *data)
1109 return mono_verifier_is_corlib (ctx->image) && !string_cmp (ctx, "System", data [MONO_TYPEDEF_NAMESPACE]) && !string_cmp (ctx, "Object", data [MONO_TYPEDEF_NAME]);
1113 decode_value (const char *_ptr, unsigned available, unsigned *value, unsigned *size)
1116 const unsigned char *ptr = (const unsigned char *)_ptr;
1124 if ((b & 0x80) == 0) {
1127 } else if ((b & 0x40) == 0) {
1131 *value = ((b & 0x3f) << 8 | ptr [1]);
1136 *value = ((b & 0x1f) << 24) |
1146 decode_signature_header (VerifyContext *ctx, guint32 offset, guint32 *size, const char **first_byte)
1148 MonoStreamHeader blob = ctx->image->heap_blob;
1149 guint32 value, enc_size;
1151 if (offset >= blob.size)
1154 if (!decode_value (blob.data + offset, blob.size - offset, &value, &enc_size))
1157 if (CHECK_ADD4_OVERFLOW_UN (offset, enc_size))
1162 if (ADD_IS_GREATER_OR_OVF (offset, value, blob.size))
1166 *first_byte = blob.data + offset;
1171 safe_read (const char **_ptr, const char *limit, unsigned *dest, int size)
1173 const char *ptr = *_ptr;
1174 if (ptr + size > limit)
1178 *dest = *((guint8*)ptr);
1182 *dest = read16 (ptr);
1186 *dest = read32 (ptr);
1195 safe_read_compressed_int (const char **_ptr, const char *limit, unsigned *dest)
1198 const char *ptr = *_ptr;
1199 gboolean res = decode_value (ptr, limit - ptr, dest, &size);
1204 #define safe_read8(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 1)
1205 #define safe_read_cint(VAR, PTR, LIMIT) safe_read_compressed_int (&PTR, LIMIT, &VAR)
1206 #define safe_read16(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 2)
1207 #define safe_read32(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 4)
1210 parse_type (VerifyContext *ctx, const char **_ptr, const char *end);
1213 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged);
1216 parse_custom_mods (VerifyContext *ctx, const char **_ptr, const char *end)
1218 const char *ptr = *_ptr;
1223 if (!safe_read8 (type, ptr, end))
1224 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the type"));
1226 if (type != MONO_TYPE_CMOD_REQD && type != MONO_TYPE_CMOD_OPT) {
1231 if (!safe_read_cint (token, ptr, end))
1232 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the token"));
1234 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token) || !get_coded_index_token (TYPEDEF_OR_REF_DESC, token))
1235 FAIL (ctx, g_strdup_printf ("CustomMod: invalid TypeDefOrRef token %x", token));
1243 parse_array_shape (VerifyContext *ctx, const char **_ptr, const char *end)
1245 const char *ptr = *_ptr;
1247 unsigned size, num, i;
1249 if (!safe_read8 (val, ptr, end))
1250 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for Rank"));
1253 FAIL (ctx, g_strdup ("ArrayShape: Invalid shape with zero Rank"));
1255 if (!safe_read_cint (size, ptr, end))
1256 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumSizes"));
1258 for (i = 0; i < size; ++i) {
1259 if (!safe_read_cint (num, ptr, end))
1260 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for Size of rank %d", i + 1));
1263 if (!safe_read_cint (size, ptr, end))
1264 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumLoBounds"));
1266 for (i = 0; i < size; ++i) {
1267 if (!safe_read_cint (num, ptr, end))
1268 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for LoBound of rank %d", i + 1));
1276 parse_generic_inst (VerifyContext *ctx, const char **_ptr, const char *end)
1278 const char *ptr = *_ptr;
1280 unsigned count, token, i;
1282 if (!safe_read8 (type, ptr, end))
1283 FAIL (ctx, g_strdup ("GenericInst: Not enough room for kind"));
1285 if (type != MONO_TYPE_CLASS && type != MONO_TYPE_VALUETYPE)
1286 FAIL (ctx, g_strdup_printf ("GenericInst: Invalid GenericInst kind %x\n", type));
1288 if (!safe_read_cint (token, ptr, end))
1289 FAIL (ctx, g_strdup ("GenericInst: Not enough room for type token"));
1291 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token) || !get_coded_index_token (TYPEDEF_OR_REF_DESC, token))
1292 FAIL (ctx, g_strdup_printf ("GenericInst: invalid TypeDefOrRef token %x", token));
1295 if (mono_metadata_token_index (ctx->token) == get_coded_index_token (TYPEDEF_OR_REF_DESC, token) &&
1296 mono_metadata_token_table (ctx->token) == get_coded_index_table (TYPEDEF_OR_REF_DESC, token))
1297 FAIL (ctx, g_strdup_printf ("Type: Recurside generic instance specification (%x). A type signature can't reference itself", ctx->token));
1300 if (!safe_read_cint (count, ptr, end))
1301 FAIL (ctx, g_strdup ("GenericInst: Not enough room for argument count"));
1304 FAIL (ctx, g_strdup ("GenericInst: Zero arguments generic instance"));
1306 for (i = 0; i < count; ++i) {
1307 if (!parse_custom_mods (ctx, &ptr, end))
1308 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1310 if (!parse_type (ctx, &ptr, end))
1311 FAIL (ctx, g_strdup_printf ("GenericInst: invalid generic argument %d", i + 1));
1318 parse_type (VerifyContext *ctx, const char **_ptr, const char *end)
1320 const char *ptr = *_ptr;
1324 if (!safe_read8 (type, ptr, end))
1325 FAIL (ctx, g_strdup ("Type: Not enough room for the type"));
1327 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_PTR) ||
1328 (type >= MONO_TYPE_VALUETYPE && type <= MONO_TYPE_GENERICINST) ||
1329 (type >= MONO_TYPE_I && type <= MONO_TYPE_U) ||
1330 (type >= MONO_TYPE_FNPTR && type <= MONO_TYPE_MVAR)))
1331 FAIL (ctx, g_strdup_printf ("Type: Invalid type kind %x\n", type));
1335 if (!parse_custom_mods (ctx, &ptr, end))
1336 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1338 if (!safe_read8 (type, ptr, end))
1339 FAIL (ctx, g_strdup ("Type: Not enough room to parse the pointer type"));
1341 if (type != MONO_TYPE_VOID) {
1343 if (!parse_type (ctx, &ptr, end))
1344 FAIL (ctx, g_strdup ("Type: Could not parse pointer type"));
1348 case MONO_TYPE_VALUETYPE:
1349 case MONO_TYPE_CLASS:
1350 if (!safe_read_cint (token, ptr, end))
1351 FAIL (ctx, g_strdup ("Type: Not enough room for the type token"));
1353 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token) || !get_coded_index_token (TYPEDEF_OR_REF_DESC, token))
1354 FAIL (ctx, g_strdup_printf ("Type: invalid TypeDefOrRef token %x", token));
1356 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, token))
1357 FAIL (ctx, g_strdup_printf ("Type: zero TypeDefOrRef token %x", token));
1359 if (mono_metadata_token_index (ctx->token) == get_coded_index_token (TYPEDEF_OR_REF_DESC, token) &&
1360 mono_metadata_token_table (ctx->token) == get_coded_index_table (TYPEDEF_OR_REF_DESC, token))
1361 FAIL (ctx, g_strdup_printf ("Type: Recursive type specification (%x). A type signature can't reference itself", ctx->token));
1366 case MONO_TYPE_MVAR:
1367 if (!safe_read_cint (token, ptr, end))
1368 FAIL (ctx, g_strdup ("Type: Not enough room for to decode generic argument number"));
1371 case MONO_TYPE_ARRAY:
1372 if (!parse_type (ctx, &ptr, end))
1373 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1374 if (!parse_array_shape (ctx, &ptr, end))
1375 FAIL (ctx, g_strdup ("Type: Could not parse array shape"));
1378 case MONO_TYPE_GENERICINST:
1379 if (!parse_generic_inst (ctx, &ptr, end))
1380 FAIL (ctx, g_strdup ("Type: Could not parse generic inst"));
1383 case MONO_TYPE_FNPTR:
1384 if (!parse_method_signature (ctx, &ptr, end, TRUE, TRUE))
1385 FAIL (ctx, g_strdup ("Type: Could not parse method pointer signature"));
1388 case MONO_TYPE_SZARRAY:
1389 if (!parse_custom_mods (ctx, &ptr, end))
1390 FAIL (ctx, g_strdup ("Type: Failed to parse array element custom attr"));
1391 if (!parse_type (ctx, &ptr, end))
1392 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1400 parse_return_type (VerifyContext *ctx, const char **_ptr, const char *end)
1405 if (!parse_custom_mods (ctx, _ptr, end))
1409 if (!safe_read8 (type, ptr, end))
1410 FAIL (ctx, g_strdup ("ReturnType: Not enough room for the type"));
1412 if (type == MONO_TYPE_VOID || type == MONO_TYPE_TYPEDBYREF) {
1417 //it's a byref, update the cursor ptr
1418 if (type == MONO_TYPE_BYREF)
1421 return parse_type (ctx, _ptr, end);
1425 parse_param (VerifyContext *ctx, const char **_ptr, const char *end)
1430 if (!parse_custom_mods (ctx, _ptr, end))
1434 if (!safe_read8 (type, ptr, end))
1435 FAIL (ctx, g_strdup ("Param: Not enough room for the type"));
1437 if (type == MONO_TYPE_TYPEDBYREF) {
1442 //it's a byref, update the cursor ptr
1443 if (type == MONO_TYPE_BYREF) {
1445 if (!parse_custom_mods (ctx, _ptr, end))
1449 return parse_type (ctx, _ptr, end);
1453 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged)
1456 unsigned param_count = 0, gparam_count = 0, type = 0, i;
1457 const char *ptr = *_ptr;
1458 gboolean saw_sentinel = FALSE;
1460 if (!safe_read8 (cconv, ptr, end))
1461 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the call conv"));
1464 FAIL (ctx, g_strdup ("MethodSig: CallConv has 0x80 set"));
1466 if (allow_unmanaged) {
1467 if ((cconv & 0x0F) > MONO_CALL_VARARG)
1468 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not valid, it's %x", cconv & 0x0F));
1469 } else if ((cconv & 0x0F) != MONO_CALL_DEFAULT && (cconv & 0x0F) != MONO_CALL_VARARG)
1470 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not Default or Vararg, it's %x", cconv & 0x0F));
1472 if ((cconv & 0x10) && !safe_read_cint (gparam_count, ptr, end))
1473 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the generic param count"));
1475 if ((cconv & 0x10) && gparam_count == 0)
1476 FAIL (ctx, g_strdup ("MethodSig: Signature with generics but zero arity"));
1478 if (allow_unmanaged && (cconv & 0x10))
1479 FAIL (ctx, g_strdup ("MethodSig: Standalone signature with generic params"));
1481 if (!safe_read_cint (param_count, ptr, end))
1482 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the param count"));
1484 if (!parse_return_type (ctx, &ptr, end))
1485 FAIL (ctx, g_strdup ("MethodSig: Error parsing return type"));
1487 for (i = 0; i < param_count; ++i) {
1488 if (allow_sentinel) {
1489 if (!safe_read8 (type, ptr, end))
1490 FAIL (ctx, g_strdup_printf ("MethodSig: Not enough room for param %d type", i));
1492 if (type == MONO_TYPE_SENTINEL) {
1493 if ((cconv & 0x0F) != MONO_CALL_VARARG)
1494 FAIL (ctx, g_strdup ("MethodSig: Found sentinel but signature is not vararg"));
1497 FAIL (ctx, g_strdup ("MethodSig: More than one sentinel type"));
1499 saw_sentinel = TRUE;
1505 if (!parse_param (ctx, &ptr, end))
1506 FAIL (ctx, g_strdup_printf ("MethodSig: Error parsing arg %d", i));
1514 parse_property_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1517 unsigned param_count = 0, i;
1518 const char *ptr = *_ptr;
1520 if (!safe_read8 (sig, ptr, end))
1521 FAIL (ctx, g_strdup ("PropertySig: Not enough room for signature"));
1523 if (sig != 0x08 && sig != 0x28)
1524 FAIL (ctx, g_strdup_printf ("PropertySig: Signature is not 0x28 or 0x08: %x", sig));
1526 if (!safe_read_cint (param_count, ptr, end))
1527 FAIL (ctx, g_strdup ("PropertySig: Not enough room for the param count"));
1529 if (!parse_custom_mods (ctx, &ptr, end))
1532 if (!parse_type (ctx, &ptr, end))
1533 FAIL (ctx, g_strdup ("PropertySig: Could not parse property type"));
1535 for (i = 0; i < param_count; ++i) {
1536 if (!parse_custom_mods (ctx, &ptr, end))
1537 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1538 if (!parse_type (ctx, &ptr, end))
1539 FAIL (ctx, g_strdup_printf ("PropertySig: Error parsing arg %d", i));
1547 parse_field (VerifyContext *ctx, const char **_ptr, const char *end)
1549 const char *ptr = *_ptr;
1550 unsigned signature = 0;
1552 if (!safe_read8 (signature, ptr, end))
1553 FAIL (ctx, g_strdup ("Field: Not enough room for field signature"));
1555 if (signature != 0x06)
1556 FAIL (ctx, g_strdup_printf ("Field: Invalid signature 0x%x, must be 6", signature));
1558 if (!parse_custom_mods (ctx, &ptr, end))
1561 if (safe_read8 (signature, ptr, end)) {
1562 if (signature != MONO_TYPE_BYREF)
1567 return parse_type (ctx, _ptr, end);
1571 parse_locals_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1574 unsigned locals_count = 0, i;
1575 const char *ptr = *_ptr;
1577 if (!safe_read8 (sig, ptr, end))
1578 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for signature"));
1581 FAIL (ctx, g_strdup_printf ("LocalsSig: Signature is not 0x28 or 0x08: %x", sig));
1583 if (!safe_read_cint (locals_count, ptr, end))
1584 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for the param count"));
1586 /* LAMEIMPL: MS sometimes generates empty local signatures and its verifier is ok with.
1587 if (locals_count == 0)
1588 FAIL (ctx, g_strdup ("LocalsSig: Signature with zero locals"));
1591 for (i = 0; i < locals_count; ++i) {
1592 if (!safe_read8 (sig, ptr, end))
1593 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1595 while (sig == MONO_TYPE_CMOD_REQD || sig == MONO_TYPE_CMOD_OPT || sig == MONO_TYPE_PINNED) {
1596 if (sig != MONO_TYPE_PINNED && !parse_custom_mods (ctx, &ptr, end))
1597 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1598 if (!safe_read8 (sig, ptr, end))
1599 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1602 if (sig == MONO_TYPE_BYREF) {
1603 if (!safe_read8 (sig, ptr, end))
1604 FAIL (ctx, g_strdup_printf ("Type: Not enough room for byref type for local %d", i));
1605 if (sig == MONO_TYPE_TYPEDBYREF)
1606 FAIL (ctx, g_strdup_printf ("Type: Invalid type typedref& for local %d", i));
1609 if (sig == MONO_TYPE_TYPEDBYREF)
1614 if (!parse_type (ctx, &ptr, end))
1615 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1623 is_valid_field_signature (VerifyContext *ctx, guint32 offset)
1626 unsigned signature = 0;
1627 const char *ptr = NULL, *end;
1629 if (!decode_signature_header (ctx, offset, &size, &ptr))
1630 FAIL (ctx, g_strdup ("FieldSig: Could not decode signature header"));
1633 if (!safe_read8 (signature, ptr, end))
1634 FAIL (ctx, g_strdup ("FieldSig: Not enough room for the signature"));
1637 FAIL (ctx, g_strdup_printf ("FieldSig: Invalid signature %x", signature));
1640 return parse_field (ctx, &ptr, end);
1644 is_valid_method_signature (VerifyContext *ctx, guint32 offset)
1647 const char *ptr = NULL, *end;
1649 if (!decode_signature_header (ctx, offset, &size, &ptr))
1650 FAIL (ctx, g_strdup ("MethodSig: Could not decode signature header"));
1653 return parse_method_signature (ctx, &ptr, end, FALSE, FALSE);
1657 is_valid_memberref_method_signature (VerifyContext *ctx, guint32 offset)
1660 const char *ptr = NULL, *end;
1662 if (!decode_signature_header (ctx, offset, &size, &ptr))
1663 FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
1666 return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1671 is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
1674 unsigned signature = 0;
1675 const char *ptr = NULL, *end;
1677 if (!decode_signature_header (ctx, offset, &size, &ptr))
1678 FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
1681 if (!safe_read8 (signature, ptr, end))
1682 FAIL (ctx, g_strdup ("MemberRefSig: Not enough room for the call conv"));
1685 if (signature == 0x06)
1686 return parse_field (ctx, &ptr, end);
1688 return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1692 is_valid_cattr_blob (VerifyContext *ctx, guint32 offset)
1695 unsigned prolog = 0;
1696 const char *ptr = NULL, *end;
1701 if (!decode_signature_header (ctx, offset, &size, &ptr))
1702 FAIL (ctx, g_strdup ("CustomAttribute: Could not decode signature header"));
1705 if (!safe_read16 (prolog, ptr, end))
1706 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1709 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1715 is_valid_cattr_type (MonoType *type)
1719 if (type->type == MONO_TYPE_OBJECT || (type->type >= MONO_TYPE_BOOLEAN && type->type <= MONO_TYPE_STRING))
1722 if (type->type == MONO_TYPE_VALUETYPE) {
1723 klass = mono_class_from_mono_type (type);
1724 return klass && klass->enumtype;
1727 if (type->type == MONO_TYPE_CLASS)
1728 return mono_class_from_mono_type (type) == mono_defaults.systemtype_class;
1734 is_valid_ser_string_full (VerifyContext *ctx, const char **str_start, guint32 *str_len, const char **_ptr, const char *end)
1737 const char *ptr = *_ptr;
1743 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string size"));
1746 if (*ptr == (char)0xFF) {
1751 if (!safe_read_cint (size, ptr, end))
1752 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string size"));
1754 if (ADDP_IS_GREATER_OR_OVF (ptr, size, end))
1755 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string"));
1765 is_valid_ser_string (VerifyContext *ctx, const char **_ptr, const char *end)
1767 const char *dummy_str;
1769 return is_valid_ser_string_full (ctx, &dummy_str, &dummy_int, _ptr, end);
1773 get_enum_by_encoded_name (VerifyContext *ctx, const char **_ptr, const char *end)
1777 const char *str_start = NULL;
1778 const char *ptr = *_ptr;
1780 guint32 str_len = 0;
1782 if (!is_valid_ser_string_full (ctx, &str_start, &str_len, &ptr, end))
1785 /*NULL or empty string*/
1786 if (str_start == NULL || str_len == 0) {
1787 ADD_ERROR_NO_RETURN (ctx, g_strdup ("CustomAttribute: Null or empty enum name"));
1791 enum_name = (char *)g_memdup (str_start, str_len + 1);
1792 enum_name [str_len] = 0;
1793 type = mono_reflection_type_from_name (enum_name, ctx->image);
1795 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute: Invalid enum class %s", enum_name));
1801 klass = mono_class_from_mono_type (type);
1802 if (!klass || !klass->enumtype) {
1803 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute:Class %s::%s is not an enum", klass->name_space, klass->name));
1812 is_valid_fixed_param (VerifyContext *ctx, MonoType *mono_type, const char **_ptr, const char *end)
1815 const char *ptr = *_ptr;
1817 guint32 element_count, i;
1820 klass = mono_type->data.klass;
1821 type = mono_type->type;
1825 case MONO_TYPE_BOOLEAN:
1832 case MONO_TYPE_CHAR:
1846 case MONO_TYPE_STRING:
1848 return is_valid_ser_string (ctx, _ptr, end);
1850 case MONO_TYPE_OBJECT: {
1851 unsigned sub_type = 0;
1852 if (!safe_read8 (sub_type, ptr, end))
1853 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array type"));
1855 if (sub_type >= MONO_TYPE_BOOLEAN && sub_type <= MONO_TYPE_STRING) {
1859 if (sub_type == MONO_TYPE_ENUM) {
1860 klass = get_enum_by_encoded_name (ctx, &ptr, end);
1864 klass = klass->element_class;
1865 type = klass->byval_arg.type;
1868 if (sub_type == 0x50) { /*Type*/
1870 return is_valid_ser_string (ctx, _ptr, end);
1872 if (sub_type == MONO_TYPE_SZARRAY) {
1873 MonoType simple_type = {{0}};
1875 if (!safe_read8 (etype, ptr, end))
1876 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array element type"));
1878 if (etype == MONO_TYPE_ENUM) {
1879 klass = get_enum_by_encoded_name (ctx, &ptr, end);
1882 } else if (etype == 0x50 || etype == MONO_TYPE_CLASS) {
1883 klass = mono_defaults.systemtype_class;
1884 } else if ((etype >= MONO_TYPE_BOOLEAN && etype <= MONO_TYPE_STRING) || etype == 0x51) {
1885 simple_type.type = etype == 0x51 ? MONO_TYPE_OBJECT : (MonoTypeEnum)etype;
1886 klass = mono_class_from_mono_type (&simple_type);
1888 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype));
1890 type = MONO_TYPE_SZARRAY;
1893 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid boxed object type %x", sub_type));
1897 case MONO_TYPE_CLASS:
1898 if (klass != mono_defaults.systemtype_class)
1899 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid class parameter type %s:%s ",klass->name_space, klass->name));
1901 return is_valid_ser_string (ctx, _ptr, end);
1903 case MONO_TYPE_VALUETYPE:
1904 if (!klass || !klass->enumtype)
1905 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid valuetype parameter expected enum %s:%s ",klass->name_space, klass->name));
1907 klass = klass->element_class;
1908 type = klass->byval_arg.type;
1911 case MONO_TYPE_SZARRAY:
1912 mono_type = &klass->byval_arg;
1913 if (!is_valid_cattr_type (mono_type))
1914 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %s:%s ",klass->name_space, klass->name));
1915 if (!safe_read32 (element_count, ptr, end))
1916 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid class parameter type %s:%s ",klass->name_space, klass->name));
1917 if (element_count == 0xFFFFFFFFu) {
1921 for (i = 0; i < element_count; ++i) {
1922 if (!is_valid_fixed_param (ctx, mono_type, &ptr, end))
1928 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid parameter type %x ", type));
1931 if (ADDP_IS_GREATER_OR_OVF (ptr, elem_size, end))
1932 FAIL (ctx, g_strdup ("CustomAttribute: Not enough space for element"));
1933 *_ptr = ptr + elem_size;
1938 is_valid_cattr_content (VerifyContext *ctx, MonoMethod *ctor, const char *ptr, guint32 size)
1941 unsigned prolog = 0;
1943 MonoMethodSignature *sig;
1948 FAIL (ctx, g_strdup ("CustomAttribute: Invalid constructor"));
1950 sig = mono_method_signature_checked (ctor, &error);
1951 if (!mono_error_ok (&error)) {
1952 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute: Invalid constructor signature %s", mono_error_get_message (&error)));
1953 mono_error_cleanup (&error);
1957 if (sig->sentinelpos != -1 || sig->call_convention == MONO_CALL_VARARG)
1958 FAIL (ctx, g_strdup ("CustomAttribute: Constructor cannot have VARAG signature"));
1962 if (!safe_read16 (prolog, ptr, end))
1963 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1966 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1968 args = sig->param_count;
1969 for (i = 0; i < args; ++i) {
1970 MonoType *arg_type = sig->params [i];
1971 if (!is_valid_fixed_param (ctx, arg_type, &ptr, end))
1975 if (!safe_read16 (num_named, ptr, end))
1976 FAIL (ctx, g_strdup ("CustomAttribute: Not enough space for num_named field"));
1978 for (i = 0; i < num_named; ++i) {
1979 MonoType *type, simple_type = {{0}};
1982 if (!safe_read8 (kind, ptr, end))
1983 FAIL (ctx, g_strdup_printf ("CustomAttribute: Not enough space for named parameter %d kind", i));
1984 if (kind != 0x53 && kind != 0x54)
1985 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid named parameter %d kind %x", i, kind));
1986 if (!safe_read8 (kind, ptr, end))
1987 FAIL (ctx, g_strdup_printf ("CustomAttribute: Not enough space for named parameter %d type", i));
1989 if (kind >= MONO_TYPE_BOOLEAN && kind <= MONO_TYPE_STRING) {
1990 simple_type.type = (MonoTypeEnum)kind;
1991 type = &simple_type;
1992 } else if (kind == MONO_TYPE_ENUM) {
1993 MonoClass *klass = get_enum_by_encoded_name (ctx, &ptr, end);
1996 type = &klass->byval_arg;
1997 } else if (kind == 0x50) {
1998 type = &mono_defaults.systemtype_class->byval_arg;
1999 } else if (kind == 0x51) {
2000 type = &mono_defaults.object_class->byval_arg;
2001 } else if (kind == MONO_TYPE_SZARRAY) {
2004 if (!safe_read8 (etype, ptr, end))
2005 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array element type"));
2007 if (etype == MONO_TYPE_ENUM) {
2008 klass = get_enum_by_encoded_name (ctx, &ptr, end);
2011 } else if (etype == 0x50 || etype == MONO_TYPE_CLASS) {
2012 klass = mono_defaults.systemtype_class;
2013 } else if ((etype >= MONO_TYPE_BOOLEAN && etype <= MONO_TYPE_STRING) || etype == 0x51) {
2014 simple_type.type = etype == 0x51 ? MONO_TYPE_OBJECT : (MonoTypeEnum)etype;
2015 klass = mono_class_from_mono_type (&simple_type);
2017 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype));
2019 type = &mono_array_class_get (klass, 1)->byval_arg;
2021 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid named parameter type %x", kind));
2024 if (!is_valid_ser_string (ctx, &ptr, end))
2027 if (!is_valid_fixed_param (ctx, type, &ptr, end))
2036 is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
2038 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2039 //TODO do proper verification
2040 return blob.size >= 1 && blob.size - 1 >= offset;
2044 is_valid_permission_set (VerifyContext *ctx, guint32 offset)
2046 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2047 //TODO do proper verification
2048 return blob.size >= 1 && blob.size - 1 >= offset;
2052 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
2055 unsigned signature = 0;
2056 const char *ptr = NULL, *end;
2058 if (!decode_signature_header (ctx, offset, &size, &ptr))
2059 FAIL (ctx, g_strdup ("StandAloneSig: Could not decode signature header"));
2062 if (!safe_read8 (signature, ptr, end))
2063 FAIL (ctx, g_strdup ("StandAloneSig: Not enough room for the call conv"));
2066 if (signature == 0x07)
2067 return parse_locals_signature (ctx, &ptr, end);
2069 /*F# and managed C++ produce standalonesig for fields even thou the spec doesn't mention it.*/
2070 if (signature == 0x06)
2071 return parse_field (ctx, &ptr, end);
2073 return parse_method_signature (ctx, &ptr, end, TRUE, TRUE);
2077 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
2080 const char *ptr = NULL, *end;
2082 if (!decode_signature_header (ctx, offset, &size, &ptr))
2083 FAIL (ctx, g_strdup ("PropertySig: Could not decode signature header"));
2086 return parse_property_signature (ctx, &ptr, end);
2090 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
2093 const char *ptr = NULL, *end;
2096 if (!decode_signature_header (ctx, offset, &size, &ptr))
2097 FAIL (ctx, g_strdup ("TypeSpec: Could not decode signature header"));
2100 if (!parse_custom_mods (ctx, &ptr, end))
2103 if (!safe_read8 (type, ptr, end))
2104 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for type"));
2106 if (type == MONO_TYPE_BYREF) {
2107 if (!safe_read8 (type, ptr, end))
2108 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for byref type"));
2109 if (type == MONO_TYPE_TYPEDBYREF)
2110 FAIL (ctx, g_strdup ("TypeSpec: Invalid type typedref&"));
2113 if (type == MONO_TYPE_TYPEDBYREF)
2117 return parse_type (ctx, &ptr, end);
2121 is_valid_methodspec_blob (VerifyContext *ctx, guint32 offset)
2124 const char *ptr = NULL, *end;
2126 unsigned count = 0, i;
2128 if (!decode_signature_header (ctx, offset, &size, &ptr))
2129 FAIL (ctx, g_strdup ("MethodSpec: Could not decode signature header"));
2132 if (!safe_read8 (type, ptr, end))
2133 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for call convention"));
2136 FAIL (ctx, g_strdup_printf ("MethodSpec: Invalid call convention 0x%x, expected 0x0A", type));
2138 if (!safe_read_cint (count, ptr, end))
2139 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for parameter count"));
2142 FAIL (ctx, g_strdup ("MethodSpec: Zero generic argument count"));
2144 for (i = 0; i < count; ++i) {
2145 if (!parse_custom_mods (ctx, &ptr, end))
2147 if (!parse_type (ctx, &ptr, end))
2148 FAIL (ctx, g_strdup_printf ("MethodSpec: Could not parse parameter %d", i + 1));
2154 is_valid_blob_object (VerifyContext *ctx, guint32 offset, guint32 minsize)
2156 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2157 guint32 entry_size, bytes;
2159 if (blob.size < offset)
2162 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
2165 if (entry_size < minsize)
2168 if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
2170 entry_size += bytes;
2172 return !ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size);
2176 is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
2178 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2179 guint32 size, entry_size, bytes;
2181 if (blob.size < offset)
2182 FAIL (ctx, g_strdup ("ContantValue: invalid offset"));
2184 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
2185 FAIL (ctx, g_strdup ("ContantValue: not enough space to decode size"));
2187 if (type == MONO_TYPE_STRING) {
2188 //String is encoded as: compressed_int:len len *bytes
2191 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size))
2192 FAIL (ctx, g_strdup_printf ("ContantValue: not enough space for string, required %d but got %d", entry_size * 2, blob.size - offset));
2198 case MONO_TYPE_BOOLEAN:
2203 case MONO_TYPE_CHAR:
2211 case MONO_TYPE_CLASS:
2221 g_assert_not_reached ();
2224 if (size != entry_size)
2225 FAIL (ctx, g_strdup_printf ("ContantValue: Expected size %d but got %d", size, entry_size));
2229 if (ADD_IS_GREATER_OR_OVF (offset, size, blob.size))
2230 FAIL (ctx, g_strdup_printf ("ContantValue: Not enough room for constant, required %d but have %d", size, blob.size - offset));
2232 if (type == MONO_TYPE_CLASS && read32 (ctx->data + blob.offset + offset))
2233 FAIL (ctx, g_strdup_printf ("ContantValue: Type is class but value is not null"));
2237 #define FAT_HEADER_INVALID_FLAGS ~(0x3 | 0x8 | 0x10 | 0xF000)
2238 //only 0x01, 0x40 and 0x80 are allowed
2239 #define SECTION_HEADER_INVALID_FLAGS 0x3E
2242 is_valid_method_header (VerifyContext *ctx, guint32 rva, guint32 *locals_token)
2244 unsigned local_vars_tok, code_size, offset = mono_cli_rva_image_map (ctx->image, rva);
2245 unsigned header = 0;
2246 unsigned fat_header = 0, size = 0, max_stack;
2247 const char *ptr = NULL, *end;
2251 if (offset == INVALID_ADDRESS)
2252 FAIL (ctx, g_strdup ("MethodHeader: Invalid RVA"));
2254 ptr = ctx->data + offset;
2255 end = ctx->data + ctx->size; /*no worries if it spawns multiple sections*/
2257 if (!safe_read8 (header, ptr, end))
2258 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for header"));
2260 switch (header & 0x3) {
2263 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid header type 0x%x", header & 0x3));
2266 if (ADDP_IS_GREATER_OR_OVF (ptr, header, end))
2267 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for method body. Required %d, but only %d is available", header, (int)(end - ptr)));
2272 if (!safe_read16 (fat_header, ptr, end))
2273 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for fat header"));
2275 size = (fat_header >> 12) & 0xF;
2277 FAIL (ctx, g_strdup ("MethodHeader: header size must be 3"));
2279 if (!safe_read16 (max_stack, ptr, end))
2280 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for max stack"));
2282 if (!safe_read32 (code_size, ptr, end))
2283 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for code size"));
2285 if (!safe_read32 (local_vars_tok, ptr, end))
2286 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for local vars tok"));
2288 if (local_vars_tok) {
2289 if (((local_vars_tok >> 24) & 0xFF) != 0x11)
2290 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature table 0x%x", ((local_vars_tok >> 24) & 0xFF)));
2291 if ((local_vars_tok & 0xFFFFFF) > ctx->image->tables [MONO_TABLE_STANDALONESIG].rows)
2292 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature points to invalid row 0x%x", local_vars_tok & 0xFFFFFF));
2293 if (!(local_vars_tok & 0xFFFFFF))
2294 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature with zero index"));
2295 *locals_token = local_vars_tok & 0xFFFFFF;
2298 if (fat_header & FAT_HEADER_INVALID_FLAGS)
2299 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid fat signature flags %x", fat_header & FAT_HEADER_INVALID_FLAGS));
2301 if (ADDP_IS_GREATER_OR_OVF (ptr, code_size, end))
2302 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for code %d", code_size));
2304 if (!(fat_header & 0x08))
2310 unsigned section_header = 0, section_size = 0;
2313 ptr = dword_align (ptr);
2314 if (!safe_read32 (section_header, ptr, end))
2315 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for data section header"));
2317 if (section_header & SECTION_HEADER_INVALID_FLAGS)
2318 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section header flags 0x%x", section_header & SECTION_HEADER_INVALID_FLAGS));
2320 is_fat = (section_header & METHOD_HEADER_SECTION_FAT_FORMAT) != 0;
2321 section_size = (section_header >> 8) & (is_fat ? 0xFFFFFF : 0xFF);
2323 if (section_size < 4)
2324 FAIL (ctx, g_strdup_printf ("MethodHeader: Section size too small"));
2326 if (ADDP_IS_GREATER_OR_OVF (ptr, section_size - 4, end)) /*must be section_size -4 as ptr was incremented by safe_read32*/
2327 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section content %d", section_size));
2329 if (section_header & METHOD_HEADER_SECTION_EHTABLE) {
2330 guint32 i, clauses = section_size / (is_fat ? 24 : 12);
2332 LAMEIMPL: MS emits section_size without accounting for header size.
2333 Mono does as the spec says. section_size is header + section
2334 MS's peverify happily accepts both.
2336 if ((clauses * (is_fat ? 24 : 12) != section_size) && (clauses * (is_fat ? 24 : 12) + 4 != section_size))
2337 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)));
2339 /* only verify the class token is verified as the rest is done by the IL verifier*/
2340 for (i = 0; i < clauses; ++i) {
2341 unsigned flags = *(unsigned char*)ptr;
2342 unsigned class_token = 0;
2343 ptr += (is_fat ? 20 : 8);
2344 if (!safe_read32 (class_token, ptr, end))
2345 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section %d", i));
2346 if (flags == MONO_EXCEPTION_CLAUSE_NONE && class_token) {
2347 guint table = mono_metadata_token_table (class_token);
2348 if (table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPESPEC)
2349 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token table %x", i, table));
2350 if (mono_metadata_token_index (class_token) > ctx->image->tables [table].rows)
2351 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token index %x", i, mono_metadata_token_index (class_token)));
2356 if (!(section_header & METHOD_HEADER_SECTION_MORE_SECTS))
2363 verify_module_table (VerifyContext *ctx)
2365 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
2366 guint32 data [MONO_MODULE_SIZE];
2368 if (table->rows != 1)
2369 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
2371 mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
2373 if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
2374 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
2376 if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
2377 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
2379 if (data [MONO_MODULE_ENC] != 0)
2380 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
2382 if (data [MONO_MODULE_ENCBASE] != 0)
2383 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
2387 verify_typeref_table (VerifyContext *ctx)
2389 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
2393 for (i = 0; i < table->rows; ++i) {
2394 mono_verifier_verify_typeref_row (ctx->image, i, &error);
2395 add_from_mono_error (ctx, &error);
2399 /*bits 9,11,14,15,19,21,24-31 */
2400 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
2402 verify_typedef_table (VerifyContext *ctx)
2404 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2405 guint32 data [MONO_TYPEDEF_SIZE];
2406 guint32 fieldlist = 1, methodlist = 1, visibility;
2409 if (table->rows == 0)
2410 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2412 for (i = 0; i < table->rows; ++i) {
2413 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2414 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
2415 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
2417 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
2418 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
2420 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
2421 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2423 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
2424 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2426 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) && (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
2427 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
2429 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
2430 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
2432 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
2433 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
2435 if (data [MONO_TYPEDEF_EXTENDS] && !is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
2436 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
2438 if (data [MONO_TYPEDEF_EXTENDS] && !get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
2439 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d zero coded extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
2441 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
2442 if ((visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) &&
2443 search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1) == -1)
2444 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d has nested visibility but no rows in the NestedClass table", i));
2446 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
2447 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
2449 if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2450 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
2452 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
2453 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));
2455 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
2456 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
2458 if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
2459 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
2461 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
2462 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));
2464 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
2465 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
2470 verify_typedef_table_full (VerifyContext *ctx)
2472 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2473 guint32 data [MONO_TYPEDEF_SIZE];
2476 if (table->rows == 0)
2477 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2479 for (i = 0; i < table->rows; ++i) {
2480 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2483 /*XXX it's ok if <module> extends object, or anything at all, actually. */
2484 /*if (data [MONO_TYPEDEF_EXTENDS] != 0)
2485 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
2490 if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
2491 if (data [MONO_TYPEDEF_EXTENDS])
2492 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
2494 gboolean is_sys_obj = typedef_is_system_object (ctx, data);
2495 gboolean has_parent = get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]) != 0;
2499 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
2502 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
2510 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
2512 verify_field_table (VerifyContext *ctx)
2514 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2515 guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
2518 module_field_list = (guint32)-1;
2519 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2520 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2521 module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
2524 for (i = 0; i < table->rows; ++i) {
2525 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2526 flags = data [MONO_FIELD_FLAGS];
2528 if (flags & INVALID_FIELD_FLAG_BITS)
2529 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
2531 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)
2532 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
2534 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
2535 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
2537 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
2538 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
2540 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
2541 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
2543 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
2544 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
2545 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
2547 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
2548 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2549 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2551 if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
2552 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2553 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
2555 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
2556 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
2557 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2559 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
2560 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
2562 if (data [MONO_FIELD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_FIELD_SIGNATURE], 1))
2563 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature blob token 0x%x", i, data [MONO_FIELD_SIGNATURE]));
2565 //TODO verify contant flag
2567 if (i + 1 < module_field_list) {
2568 guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
2569 if (!(flags & FIELD_ATTRIBUTE_STATIC))
2570 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
2571 if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
2572 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
2578 verify_field_table_full (VerifyContext *ctx)
2580 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2581 guint32 data [MONO_FIELD_SIZE];
2584 for (i = 0; i < table->rows; ++i) {
2585 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2587 if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
2588 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
2592 /*bits 8,9,10,11,13,14,15*/
2593 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
2595 verify_method_table (VerifyContext *ctx)
2597 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2598 guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
2599 guint32 paramlist = 1;
2600 gboolean is_ctor, is_cctor;
2604 module_method_list = (guint32)-1;
2605 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2606 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2607 module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
2610 for (i = 0; i < table->rows; ++i) {
2611 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2612 rva = data [MONO_METHOD_RVA];
2613 implflags = data [MONO_METHOD_IMPLFLAGS];
2614 flags = data [MONO_METHOD_FLAGS];
2615 access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
2616 code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
2619 if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
2620 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
2623 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
2625 if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
2626 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
2628 name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
2629 is_ctor = !strcmp (".ctor", name);
2630 is_cctor = !strcmp (".cctor", name);
2632 if ((is_ctor || is_cctor) &&
2633 search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
2634 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
2636 if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
2637 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
2639 if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
2640 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
2641 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
2642 if (flags & METHOD_ATTRIBUTE_FINAL)
2643 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and Final", i));
2644 if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
2645 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
2648 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
2649 ADD_WARNING (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
2651 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
2652 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
2654 //XXX no checks against cas stuff 10,11,12,13)
2656 //TODO check iface with .ctor (15,16)
2658 if (i + 1 < module_method_list) {
2659 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2660 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
2661 if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
2662 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
2663 if (access == METHOD_ATTRIBUTE_FAMILY || access == METHOD_ATTRIBUTE_FAM_AND_ASSEM || access == METHOD_ATTRIBUTE_FAM_OR_ASSEM)
2664 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public, Private or Assembly", i));
2667 //TODO check valuetype for synchronized
2669 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
2670 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
2672 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
2673 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
2674 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
2675 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2676 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but not Static", i));
2679 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
2680 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2681 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
2683 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
2684 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
2686 //TODO check signature contents
2689 if ((flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) || (implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
2690 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is either Abstract, InternalCall or PinvokeImpl", i));
2691 if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
2692 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
2694 if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2695 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
2698 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2700 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
2701 if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
2702 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
2704 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
2705 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
2707 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
2708 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
2710 if (data [MONO_METHOD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHOD_SIGNATURE], 1))
2711 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature blob token 0x%x", i, data [MONO_METHOD_SIGNATURE]));
2713 if (data [MONO_METHOD_PARAMLIST] == 0)
2714 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
2716 if (data [MONO_METHOD_PARAMLIST] < paramlist)
2717 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));
2719 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
2720 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
2722 paramlist = data [MONO_METHOD_PARAMLIST];
2728 verify_method_table_full (VerifyContext *ctx)
2730 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2731 guint32 data [MONO_METHOD_SIZE], rva, locals_token;
2734 for (i = 0; i < table->rows; ++i) {
2735 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2736 rva = data [MONO_METHOD_RVA];
2738 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
2739 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
2741 if (rva && !is_valid_method_header (ctx, rva, &locals_token))
2742 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
2747 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
2749 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2750 guint32 row = *current_method;
2751 guint32 paramlist, tmp;
2754 paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
2755 while (row < table->rows) {
2756 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
2757 if (tmp > paramlist) {
2758 *current_method = row;
2759 return tmp - paramlist;
2764 /*no more methods, all params apply to the last one*/
2765 *current_method = table->rows;
2770 #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))
2772 verify_param_table (VerifyContext *ctx)
2774 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
2775 guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
2776 gboolean first_param = TRUE;
2779 if (ctx->image->tables [MONO_TABLE_METHOD].rows == 0) {
2780 if (table->rows > 0)
2781 ADD_ERROR (ctx, g_strdup ("Param table has rows while the method table has zero"));
2785 remaining_params = get_next_param_count (ctx, ¤t_method);
2787 for (i = 0; i < table->rows; ++i) {
2788 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
2789 flags = data [MONO_PARAM_FLAGS];
2791 if (flags & INVALID_PARAM_FLAGS_BITS)
2792 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
2794 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
2795 if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
2796 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
2798 if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
2799 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
2802 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)
2803 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
2805 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
2806 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
2808 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
2809 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
2811 first_param = FALSE;
2812 sequence = data [MONO_PARAM_SEQUENCE];
2813 if (--remaining_params == 0) {
2814 remaining_params = get_next_param_count (ctx, ¤t_method);
2821 verify_interfaceimpl_table (VerifyContext *ctx)
2823 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
2824 guint32 data [MONO_INTERFACEIMPL_SIZE];
2827 for (i = 0; i < table->rows; ++i) {
2828 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
2829 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2830 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_INTERFACEIMPL_CLASS]));
2832 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2833 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
2835 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2836 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
2841 verify_memberref_table (VerifyContext *ctx)
2843 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2844 guint32 data [MONO_MEMBERREF_SIZE];
2847 for (i = 0; i < table->rows; ++i) {
2848 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2850 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2851 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
2853 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2854 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
2856 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
2857 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
2859 if (data [MONO_MEMBERREF_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_MEMBERREF_SIGNATURE], 1))
2860 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d invalid signature blob token 0x%x", i, data [MONO_MEMBERREF_SIGNATURE]));
2866 verify_memberref_table_full (VerifyContext *ctx)
2868 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2869 guint32 data [MONO_MEMBERREF_SIZE];
2872 for (i = 0; i < table->rows; ++i) {
2873 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2875 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
2876 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field 0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
2881 verify_constant_table (VerifyContext *ctx)
2883 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
2884 guint32 data [MONO_CONSTANT_SIZE], type;
2887 for (i = 0; i < table->rows; ++i) {
2888 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
2889 type = data [MONO_CONSTANT_TYPE];
2891 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
2892 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
2894 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2895 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
2897 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2898 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
2900 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
2901 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
2906 verify_cattr_table (VerifyContext *ctx)
2908 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2909 guint32 data [MONO_CUSTOM_ATTR_SIZE];
2912 for (i = 0; i < table->rows; ++i) {
2913 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2915 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
2916 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2918 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]))
2919 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Type field 0x%08x", i, data [MONO_CUSTOM_ATTR_TYPE]));
2921 if (data [MONO_CUSTOM_ATTR_VALUE] && !is_valid_blob_object (ctx, data [MONO_CUSTOM_ATTR_VALUE], 0))
2922 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d invalid value blob 0x%x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2927 verify_cattr_table_full (VerifyContext *ctx)
2930 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2933 guint32 data [MONO_CUSTOM_ATTR_SIZE], mtoken, size;
2936 for (i = 0; i < table->rows; ++i) {
2937 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2939 if (!is_valid_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
2940 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2942 mtoken = data [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
2943 switch (data [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
2944 case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
2945 mtoken |= MONO_TOKEN_METHOD_DEF;
2947 case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
2948 mtoken |= MONO_TOKEN_MEMBER_REF;
2951 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute constructor row %d Token 0x%08x", i, data [MONO_CUSTOM_ATTR_TYPE]));
2954 ctor = mono_get_method_checked (ctx->image, mtoken, NULL, NULL, &error);
2957 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute content row %d Could not load ctor due to %s", i, mono_error_get_message (&error)));
2958 mono_error_cleanup (&error);
2961 /*This can't fail since this is checked in is_valid_cattr_blob*/
2962 g_assert (decode_signature_header (ctx, data [MONO_CUSTOM_ATTR_VALUE], &size, &ptr));
2964 if (!is_valid_cattr_content (ctx, ctor, ptr, size))
2965 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute content row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2970 verify_field_marshal_table (VerifyContext *ctx)
2972 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2973 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2976 for (i = 0; i < table->rows; ++i) {
2977 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2979 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2980 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
2982 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2983 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
2985 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
2986 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
2988 if (!is_valid_blob_object (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE], 1))
2989 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d invalid NativeType blob 0x%x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2994 verify_field_marshal_table_full (VerifyContext *ctx)
2996 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2997 guint32 data [MONO_FIELD_MARSHAL_SIZE];
3000 for (i = 0; i < table->rows; ++i) {
3001 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
3003 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
3004 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
3009 verify_decl_security_table (VerifyContext *ctx)
3011 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
3012 guint32 data [MONO_DECL_SECURITY_SIZE];
3015 for (i = 0; i < table->rows; ++i) {
3016 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
3018 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
3019 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
3021 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
3022 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
3024 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
3025 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
3030 verify_decl_security_table_full (VerifyContext *ctx)
3032 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
3033 guint32 data [MONO_DECL_SECURITY_SIZE];
3036 for (i = 0; i < table->rows; ++i) {
3037 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
3039 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
3040 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
3045 verify_class_layout_table (VerifyContext *ctx)
3047 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
3048 guint32 data [MONO_CLASS_LAYOUT_SIZE];
3051 for (i = 0; i < table->rows; ++i) {
3052 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
3054 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3055 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
3057 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
3069 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
3075 verify_field_layout_table (VerifyContext *ctx)
3077 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
3078 guint32 data [MONO_FIELD_LAYOUT_SIZE];
3081 for (i = 0; i < table->rows; ++i) {
3082 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
3084 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
3085 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
3090 verify_standalonesig_table (VerifyContext *ctx)
3092 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
3093 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
3096 for (i = 0; i < table->rows; ++i) {
3097 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
3099 if (data [MONO_STAND_ALONE_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_STAND_ALONE_SIGNATURE], 1))
3100 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d invalid signature 0x%x", i, data [MONO_STAND_ALONE_SIGNATURE]));
3105 verify_standalonesig_table_full (VerifyContext *ctx)
3107 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
3108 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
3111 for (i = 0; i < table->rows; ++i) {
3112 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
3114 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
3115 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
3120 verify_eventmap_table (VerifyContext *ctx)
3122 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
3123 guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
3126 for (i = 0; i < table->rows; ++i) {
3127 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
3129 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3130 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
3132 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
3133 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
3135 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
3139 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
3141 verify_event_table (VerifyContext *ctx)
3143 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
3144 guint32 data [MONO_EVENT_SIZE];
3147 for (i = 0; i < table->rows; ++i) {
3148 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
3150 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
3151 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
3153 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
3154 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
3156 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
3157 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
3162 verify_event_table_full (VerifyContext *ctx)
3164 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
3165 MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
3166 guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
3167 gboolean found_add, found_remove;
3170 for (i = 0; i < table->rows; ++i) {
3171 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
3173 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
3174 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
3176 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
3178 //first we move to the first row for this event
3180 if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
3184 //now move forward looking for AddOn and RemoveOn rows
3185 found_add = found_remove = FALSE;
3186 while (idx < sema_table->rows) {
3187 mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
3188 if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
3190 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
3192 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
3193 found_remove = TRUE;
3194 if (found_add && found_remove)
3200 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
3202 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no RemoveOn associated method", i));
3207 verify_propertymap_table (VerifyContext *ctx)
3209 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
3210 guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
3213 for (i = 0; i < table->rows; ++i) {
3214 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
3216 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3217 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
3219 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
3220 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
3222 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
3226 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
3228 verify_property_table (VerifyContext *ctx)
3230 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
3231 guint32 data [MONO_PROPERTY_SIZE];
3234 for (i = 0; i < table->rows; ++i) {
3235 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
3237 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
3238 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
3240 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
3241 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
3243 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
3244 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
3246 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
3247 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
3248 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
3254 verify_methodimpl_table (VerifyContext *ctx)
3256 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
3257 guint32 data [MONO_METHODIMPL_SIZE];
3260 for (i = 0; i < table->rows; ++i) {
3261 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
3263 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3264 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
3266 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
3267 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
3269 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
3270 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
3272 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
3273 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
3275 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
3276 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
3281 verify_moduleref_table (VerifyContext *ctx)
3283 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
3284 guint32 data [MONO_MODULEREF_SIZE];
3287 for (i = 0; i < table->rows; ++i) {
3288 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
3290 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
3291 ADD_ERROR (ctx, g_strdup_printf ("Invalid ModuleRef row %d name field %08x", i, data [MONO_MODULEREF_NAME]));
3296 verify_typespec_table (VerifyContext *ctx)
3298 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
3299 guint32 data [MONO_TYPESPEC_SIZE];
3302 for (i = 0; i < table->rows; ++i) {
3303 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
3305 if (data [MONO_TYPESPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_TYPESPEC_SIGNATURE], 1))
3306 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
3311 verify_typespec_table_full (VerifyContext *ctx)
3313 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
3314 guint32 data [MONO_TYPESPEC_SIZE];
3317 for (i = 0; i < table->rows; ++i) {
3318 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
3319 ctx->token = (i + 1) | MONO_TOKEN_TYPE_SPEC;
3320 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
3321 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
3326 #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))
3328 verify_implmap_table (VerifyContext *ctx)
3330 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
3331 guint32 data [MONO_IMPLMAP_SIZE], cconv;
3334 for (i = 0; i < table->rows; ++i) {
3335 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
3337 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
3338 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
3340 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
3341 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
3342 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
3344 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
3345 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
3347 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
3348 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
3350 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
3351 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
3353 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
3354 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
3356 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULEREF].rows)
3357 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
3362 verify_fieldrva_table (VerifyContext *ctx)
3364 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
3365 guint32 data [MONO_FIELD_RVA_SIZE];
3368 for (i = 0; i < table->rows; ++i) {
3369 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
3371 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
3372 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
3374 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
3375 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
3379 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 14) | (1 << 15))
3381 verify_assembly_table (VerifyContext *ctx)
3383 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
3384 guint32 data [MONO_ASSEMBLY_SIZE], hash;
3387 if (table->rows > 1)
3388 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
3390 for (i = 0; i < table->rows; ++i) {
3391 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
3393 hash = data [MONO_ASSEMBLY_HASH_ALG];
3394 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
3395 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
3397 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
3398 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
3400 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY], 1))
3401 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
3403 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
3404 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
3406 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
3407 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
3411 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~((1 << 0) | (1 << 8) | (1 << 14) | (1 << 15))
3413 verify_assemblyref_table (VerifyContext *ctx)
3415 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
3416 guint32 data [MONO_ASSEMBLYREF_SIZE];
3419 for (i = 0; i < table->rows; ++i) {
3420 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
3422 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
3423 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
3425 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY], 1))
3426 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
3428 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
3429 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
3431 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
3432 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
3434 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE], 1))
3435 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
3439 #define INVALID_FILE_FLAGS_BITS ~(1)
3441 verify_file_table (VerifyContext *ctx)
3443 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
3444 guint32 data [MONO_FILE_SIZE];
3447 for (i = 0; i < table->rows; ++i) {
3448 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
3450 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
3451 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
3453 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
3454 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
3456 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE], 1))
3457 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
3461 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
3463 verify_exportedtype_table (VerifyContext *ctx)
3465 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
3466 guint32 data [MONO_EXP_TYPE_SIZE];
3469 for (i = 0; i < table->rows; ++i) {
3470 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
3472 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
3473 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
3475 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
3476 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
3478 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
3479 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
3481 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3482 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
3484 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3485 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
3487 /*nested type can't have a namespace*/
3488 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
3489 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
3493 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
3495 verify_manifest_resource_table (VerifyContext *ctx)
3497 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)ctx->image->image_info;
3498 MonoCLIHeader *ch = &iinfo->cli_cli_header;
3499 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
3500 guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
3503 resources_size = ch->ch_resources.size;
3505 for (i = 0; i < table->rows; ++i) {
3506 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
3508 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
3509 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
3511 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
3512 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
3514 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
3515 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
3517 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
3518 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
3520 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3521 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3523 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
3524 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])));
3526 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
3527 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
3529 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
3530 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
3535 verify_nested_class_table (VerifyContext *ctx)
3537 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3538 guint32 data [MONO_NESTED_CLASS_SIZE];
3541 for (i = 0; i < table->rows; ++i) {
3542 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
3544 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3545 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
3546 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3547 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3548 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
3549 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3553 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
3555 verify_generic_param_table (VerifyContext *ctx)
3557 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
3558 guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
3559 int i, param_number = 0;
3561 for (i = 0; i < table->rows; ++i) {
3562 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
3564 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
3565 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
3567 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
3568 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
3570 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
3571 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
3573 token = data [MONO_GENERICPARAM_OWNER];
3575 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
3576 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
3578 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
3579 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
3581 if (token != last_token) {
3586 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
3587 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));
3594 verify_method_spec_table (VerifyContext *ctx)
3596 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3597 guint32 data [MONO_METHODSPEC_SIZE];
3600 for (i = 0; i < table->rows; ++i) {
3601 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3603 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3604 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
3606 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3607 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
3609 if (data [MONO_METHODSPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHODSPEC_SIGNATURE], 1))
3610 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid signature token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3615 verify_method_spec_table_full (VerifyContext *ctx)
3617 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3618 guint32 data [MONO_METHODSPEC_SIZE];
3621 for (i = 0; i < table->rows; ++i) {
3622 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3624 if (!is_valid_methodspec_blob (ctx, data [MONO_METHODSPEC_SIGNATURE]))
3625 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3630 verify_generic_param_constraint_table (VerifyContext *ctx)
3632 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
3633 guint32 data [MONO_GENPARCONSTRAINT_SIZE];
3635 guint32 last_owner = 0, last_constraint = 0;
3637 for (i = 0; i < table->rows; ++i) {
3638 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
3640 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
3641 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_GENPARCONSTRAINT_GENERICPAR]));
3643 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3644 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
3646 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3647 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
3649 if (last_owner > data [MONO_GENPARCONSTRAINT_GENERICPAR])
3650 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d is not properly sorted. Previous value of the owner column is 0x%08x current value is 0x%08x", i, last_owner, data [MONO_GENPARCONSTRAINT_GENERICPAR]));
3652 if (last_owner == data [MONO_GENPARCONSTRAINT_GENERICPAR]) {
3653 if (last_constraint == data [MONO_GENPARCONSTRAINT_CONSTRAINT])
3654 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has duplicate constraint 0x%08x", i, last_constraint));
3656 last_owner = data [MONO_GENPARCONSTRAINT_GENERICPAR];
3658 last_constraint = data [MONO_GENPARCONSTRAINT_CONSTRAINT];
3665 const char *name_space;
3666 guint32 resolution_scope;
3670 typedef_hash (gconstpointer _key)
3672 const TypeDefUniqueId *key = (const TypeDefUniqueId *)_key;
3673 return g_str_hash (key->name) ^ g_str_hash (key->name_space) ^ key->resolution_scope; /*XXX better salt the int key*/
3677 typedef_equals (gconstpointer _a, gconstpointer _b)
3679 const TypeDefUniqueId *a = (const TypeDefUniqueId *)_a;
3680 const TypeDefUniqueId *b = (const TypeDefUniqueId *)_b;
3681 return !strcmp (a->name, b->name) && !strcmp (a->name_space, b->name_space) && a->resolution_scope == b->resolution_scope;
3685 verify_typedef_table_global_constraints (VerifyContext *ctx)
3688 guint32 data [MONO_TYPEDEF_SIZE];
3689 guint32 nested_data [MONO_NESTED_CLASS_SIZE];
3690 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
3691 MonoTableInfo *nested_table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3692 GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3694 for (i = 0; i < table->rows; ++i) {
3696 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3697 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
3699 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAME]);
3700 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAMESPACE]);
3701 type->resolution_scope = 0;
3703 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
3704 if (visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) {
3705 int res = search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1);
3706 g_assert (res >= 0);
3708 mono_metadata_decode_row (nested_table, res, nested_data, MONO_NESTED_CLASS_SIZE);
3709 type->resolution_scope = nested_data [MONO_NESTED_CLASS_ENCLOSING];
3712 if (g_hash_table_lookup (unique_types, type)) {
3713 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));
3714 g_hash_table_destroy (unique_types);
3718 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3721 g_hash_table_destroy (unique_types);
3725 verify_typeref_table_global_constraints (VerifyContext *ctx)
3728 guint32 data [MONO_TYPEREF_SIZE];
3729 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
3730 GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3732 for (i = 0; i < table->rows; ++i) {
3733 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3734 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
3736 type->resolution_scope = data [MONO_TYPEREF_SCOPE];
3737 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAME]);
3738 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAMESPACE]);
3740 if (g_hash_table_lookup (unique_types, type)) {
3741 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));
3742 g_hash_table_destroy (unique_types);
3746 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3749 g_hash_table_destroy (unique_types);
3753 verify_tables_data_global_constraints (VerifyContext *ctx)
3755 verify_typedef_table_global_constraints (ctx);
3759 verify_tables_data_global_constraints_full (VerifyContext *ctx)
3761 verify_typeref_table (ctx);
3762 verify_typeref_table_global_constraints (ctx);
3766 verify_tables_data (VerifyContext *ctx)
3768 OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
3769 guint32 size = 0, tables_offset;
3772 for (i = 0; i < 0x2D; ++i) {
3773 MonoTableInfo *table = &ctx->image->tables [i];
3775 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
3776 if (tmp_size < size) {
3784 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
3786 tables_offset = ctx->image->tables_base - ctx->data;
3787 if (!bounds_check_offset (&tables_area, tables_offset, size))
3788 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)));
3790 verify_module_table (ctx);
3792 /*Obfuscators love to place broken stuff in the typeref table
3793 verify_typeref_table (ctx);
3795 verify_typedef_table (ctx);
3797 verify_field_table (ctx);
3799 verify_method_table (ctx);
3801 verify_param_table (ctx);
3803 verify_interfaceimpl_table (ctx);
3805 verify_memberref_table (ctx);
3807 verify_constant_table (ctx);
3809 verify_cattr_table (ctx);
3811 verify_field_marshal_table (ctx);
3813 verify_decl_security_table (ctx);
3815 verify_class_layout_table (ctx);
3817 verify_field_layout_table (ctx);
3819 verify_standalonesig_table (ctx);
3821 verify_eventmap_table (ctx);
3823 verify_event_table (ctx);
3825 verify_propertymap_table (ctx);
3827 verify_property_table (ctx);
3829 verify_methodimpl_table (ctx);
3831 verify_moduleref_table (ctx);
3833 verify_typespec_table (ctx);
3835 verify_implmap_table (ctx);
3837 verify_fieldrva_table (ctx);
3839 verify_assembly_table (ctx);
3841 verify_assemblyref_table (ctx);
3843 verify_file_table (ctx);
3845 verify_exportedtype_table (ctx);
3847 verify_manifest_resource_table (ctx);
3849 verify_nested_class_table (ctx);
3851 verify_generic_param_table (ctx);
3853 verify_method_spec_table (ctx);
3855 verify_generic_param_constraint_table (ctx);
3857 verify_tables_data_global_constraints (ctx);
3861 init_verify_context (VerifyContext *ctx, MonoImage *image, gboolean report_error)
3863 memset (ctx, 0, sizeof (VerifyContext));
3865 ctx->report_error = report_error;
3866 ctx->report_warning = FALSE; //export this setting in the API
3868 ctx->size = image->raw_data_len;
3869 ctx->data = image->raw_data;
3873 cleanup_context (VerifyContext *ctx, GSList **error_list)
3875 g_free (ctx->sections);
3877 *error_list = ctx->errors;
3879 mono_free_verify_list (ctx->errors);
3884 cleanup_context_checked (VerifyContext *ctx, MonoError *error)
3886 g_free (ctx->sections);
3888 MonoVerifyInfo *info = (MonoVerifyInfo *)ctx->errors->data;
3889 mono_error_set_bad_image (error, ctx->image, "%s", info->message);
3890 mono_free_verify_list (ctx->errors);
3896 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3900 if (!mono_verifier_is_enabled_for_image (image))
3903 init_verify_context (&ctx, image, error_list != NULL);
3904 ctx.stage = STAGE_PE;
3906 verify_msdos_header (&ctx);
3908 verify_pe_header (&ctx);
3910 verify_pe_optional_header (&ctx);
3912 load_section_table (&ctx);
3914 load_data_directories (&ctx);
3916 verify_import_table (&ctx);
3918 /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
3919 verify_resources_table (&ctx);
3922 return cleanup_context (&ctx, error_list);
3926 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3930 if (!mono_verifier_is_enabled_for_image (image))
3933 init_verify_context (&ctx, image, error_list != NULL);
3934 ctx.stage = STAGE_CLI;
3936 verify_cli_header (&ctx);
3938 verify_metadata_header (&ctx);
3940 verify_tables_schema (&ctx);
3943 return cleanup_context (&ctx, error_list);
3948 * Verifies basic table constraints such as global table invariants (sorting, field monotonicity, etc).
3949 * Other verification checks are meant to be done lazily by the runtime. Those include:
3950 * blob items (signatures, method headers, custom attributes, etc)
3951 * type semantics related
3953 * stuff that should not block other pieces from running such as bad types/methods/fields/etc.
3955 * The whole idea is that if this succeed the runtime is free to play around safely but any complex
3956 * operation still need more checking.
3959 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3963 if (!mono_verifier_is_enabled_for_image (image))
3966 init_verify_context (&ctx, image, error_list != NULL);
3967 ctx.stage = STAGE_TABLES;
3969 verify_tables_data (&ctx);
3971 return cleanup_context (&ctx, error_list);
3976 * Verifies all other constraints.
3979 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3983 if (!mono_verifier_is_enabled_for_image (image))
3986 init_verify_context (&ctx, image, error_list != NULL);
3987 ctx.stage = STAGE_TABLES;
3989 verify_typedef_table_full (&ctx);
3991 verify_field_table_full (&ctx);
3993 verify_method_table_full (&ctx);
3995 verify_memberref_table_full (&ctx);
3997 verify_cattr_table_full (&ctx);
3999 verify_field_marshal_table_full (&ctx);
4001 verify_decl_security_table_full (&ctx);
4003 verify_standalonesig_table_full (&ctx);
4005 verify_event_table_full (&ctx);
4007 verify_typespec_table_full (&ctx);
4009 verify_method_spec_table_full (&ctx);
4011 verify_tables_data_global_constraints_full (&ctx);
4014 return cleanup_context (&ctx, error_list);
4018 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4022 if (!mono_verifier_is_enabled_for_image (image))
4025 init_verify_context (&ctx, image, error_list != NULL);
4026 ctx.stage = STAGE_TABLES;
4028 is_valid_field_signature (&ctx, offset);
4029 return cleanup_context (&ctx, error_list);
4033 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
4036 guint32 locals_token;
4038 if (!mono_verifier_is_enabled_for_image (image))
4041 init_verify_context (&ctx, image, error_list != NULL);
4042 ctx.stage = STAGE_TABLES;
4044 is_valid_method_header (&ctx, offset, &locals_token);
4046 guint32 sig_offset = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_STANDALONESIG], locals_token - 1, MONO_STAND_ALONE_SIGNATURE);
4047 is_valid_standalonesig_blob (&ctx, sig_offset);
4050 return cleanup_context (&ctx, error_list);
4054 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, MonoError *error)
4060 if (!mono_verifier_is_enabled_for_image (image))
4063 init_verify_context (&ctx, image, TRUE);
4064 ctx.stage = STAGE_TABLES;
4066 is_valid_method_signature (&ctx, offset);
4067 /*XXX This returns a bad image exception, it might be the case that the right exception is method load.*/
4068 return cleanup_context_checked (&ctx, error);
4072 mono_verifier_verify_memberref_method_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_memberref_method_signature (&ctx, offset);
4083 return cleanup_context (&ctx, error_list);
4087 mono_verifier_verify_memberref_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4091 if (!mono_verifier_is_enabled_for_image (image))
4094 init_verify_context (&ctx, image, error_list != NULL);
4095 ctx.stage = STAGE_TABLES;
4097 is_valid_field_signature (&ctx, offset);
4098 return cleanup_context (&ctx, error_list);
4102 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
4106 if (!mono_verifier_is_enabled_for_image (image))
4109 init_verify_context (&ctx, image, error_list != NULL);
4110 ctx.stage = STAGE_TABLES;
4112 is_valid_standalonesig_blob (&ctx, offset);
4113 return cleanup_context (&ctx, error_list);
4117 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
4121 if (!mono_verifier_is_enabled_for_image (image))
4124 init_verify_context (&ctx, image, error_list != NULL);
4125 ctx.stage = STAGE_TABLES;
4128 is_valid_typespec_blob (&ctx, offset);
4129 return cleanup_context (&ctx, error_list);
4133 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
4137 if (!mono_verifier_is_enabled_for_image (image))
4140 init_verify_context (&ctx, image, error_list != NULL);
4141 ctx.stage = STAGE_TABLES;
4143 is_valid_methodspec_blob (&ctx, offset);
4144 return cleanup_context (&ctx, error_list);
4148 verify_user_string (VerifyContext *ctx, guint32 offset)
4150 OffsetAndSize heap_us = get_metadata_stream (ctx, &ctx->image->heap_us);
4151 guint32 entry_size, bytes;
4153 if (heap_us.size < offset)
4154 ADD_ERROR (ctx, g_strdup ("User string offset beyond heap_us size"));
4156 if (!decode_value (ctx->data + offset + heap_us.offset, heap_us.size - heap_us.offset, &entry_size, &bytes))
4157 ADD_ERROR (ctx, g_strdup ("Could not decode user string blob size"));
4159 if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
4160 ADD_ERROR (ctx, g_strdup ("User string size overflow"));
4162 entry_size += bytes;
4164 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, heap_us.size))
4165 ADD_ERROR (ctx, g_strdup ("User string oveflow heap_us"));
4169 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
4173 if (!mono_verifier_is_enabled_for_image (image))
4176 init_verify_context (&ctx, image, error_list != NULL);
4177 ctx.stage = STAGE_TABLES;
4179 verify_user_string (&ctx, offset);
4181 return cleanup_context (&ctx, error_list);
4185 mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, GSList **error_list)
4189 if (!mono_verifier_is_enabled_for_image (image))
4192 init_verify_context (&ctx, image, error_list != NULL);
4193 ctx.stage = STAGE_TABLES;
4195 is_valid_cattr_blob (&ctx, offset);
4197 return cleanup_context (&ctx, error_list);
4201 mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, GSList **error_list)
4205 if (!mono_verifier_is_enabled_for_image (image))
4208 init_verify_context (&ctx, image, error_list != NULL);
4209 ctx.stage = STAGE_TABLES;
4211 is_valid_cattr_content (&ctx, ctor, (const char*)data, size);
4213 return cleanup_context (&ctx, error_list);
4217 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
4219 MonoMethodSignature *original_sig;
4220 if (!mono_verifier_is_enabled_for_image (image))
4223 original_sig = mono_method_signature (method);
4224 if (original_sig->call_convention == MONO_CALL_VARARG) {
4225 if (original_sig->hasthis != signature->hasthis)
4227 if (original_sig->call_convention != signature->call_convention)
4229 if (original_sig->explicit_this != signature->explicit_this)
4231 if (original_sig->pinvoke != signature->pinvoke)
4233 if (original_sig->sentinelpos != signature->sentinelpos)
4235 } else if (!mono_metadata_signature_equal (signature, original_sig)) {
4243 mono_verifier_verify_typeref_row (MonoImage *image, guint32 row, MonoError *error)
4245 MonoTableInfo *table = &image->tables [MONO_TABLE_TYPEREF];
4246 guint32 data [MONO_TYPEREF_SIZE];
4250 if (!mono_verifier_is_enabled_for_image (image))
4253 if (row >= table->rows) {
4254 mono_error_set_bad_image (error, image, "Invalid typeref row %d - table has %d rows", row, table->rows);
4258 mono_metadata_decode_row (table, row, data, MONO_TYPEREF_SIZE);
4259 if (!is_valid_coded_index_with_image (image, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE])) {
4260 mono_error_set_bad_image (error, image, "Invalid typeref row %d coded index 0x%08x", row, data [MONO_TYPEREF_SCOPE]);
4264 if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE])) {
4265 mono_error_set_bad_image (error, image, "The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", row);
4269 if (!data [MONO_TYPEREF_NAME] || !is_valid_string_full_with_image (image, data [MONO_TYPEREF_NAME], FALSE)) {
4270 mono_error_set_bad_image (error, image, "Invalid typeref row %d name token 0x%08x", row, data [MONO_TYPEREF_NAME]);
4274 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_string_full_with_image (image, data [MONO_TYPEREF_NAMESPACE], FALSE)) {
4275 mono_error_set_bad_image (error, image, "Invalid typeref row %d namespace token 0x%08x", row, data [MONO_TYPEREF_NAMESPACE]);
4282 /*Perform additional verification including metadata ones*/
4284 mono_verifier_verify_methodimpl_row (MonoImage *image, guint32 row, MonoError *error)
4286 MonoMethod *declaration, *body;
4287 MonoMethodSignature *body_sig, *decl_sig;
4288 MonoTableInfo *table = &image->tables [MONO_TABLE_METHODIMPL];
4289 guint32 data [MONO_METHODIMPL_SIZE];
4293 if (!mono_verifier_is_enabled_for_image (image))
4296 if (row >= table->rows) {
4297 mono_error_set_bad_image (error, image, "Invalid methodimpl row %d - table has %d rows", row, table->rows);
4301 mono_metadata_decode_row (table, row, data, MONO_METHODIMPL_SIZE);
4303 body = method_from_method_def_or_ref (image, data [MONO_METHODIMPL_BODY], NULL, error);
4307 declaration = method_from_method_def_or_ref (image, data [MONO_METHODIMPL_DECLARATION], NULL, error);
4312 mono_class_setup_supertypes (class);
4313 if (!mono_class_has_parent (class, body->klass)) {
4314 mono_error_set_bad_image (error, image, "Invalid methodimpl body doesn't belong to parent for row %x", row);
4318 if (!(body_sig = mono_method_signature_checked (body, error))) {
4322 if (!(decl_sig = mono_method_signature_checked (declaration, error))) {
4326 if (!mono_verifier_is_signature_compatible (decl_sig, body_sig)) {
4327 mono_error_set_bad_image (error, image, "Invalid methodimpl body signature not compatible with declaration row %x", row);
4336 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
4342 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
4348 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
4354 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
4360 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4366 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
4372 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, MonoError *error)
4379 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
4385 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
4391 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
4397 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
4403 mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, GSList **error_list)
4409 mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, GSList **error_list)
4415 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
4422 mono_verifier_verify_typeref_row (MonoImage *image, guint32 row, MonoError *error)
4429 mono_verifier_verify_methodimpl_row (MonoImage *image, guint32 row, MonoError *error)
4436 mono_verifier_verify_memberref_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
4442 mono_verifier_verify_memberref_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4447 #endif /* DISABLE_VERIFIER */