3 * Metadata verfication support
6 * Mono Project (http://www.mono-project.com)
8 * Copyright (C) 2005-2008 Novell, Inc. (http://www.novell.com)
9 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
11 #include <mono/metadata/object-internals.h>
12 #include <mono/metadata/verify.h>
13 #include <mono/metadata/verify-internals.h>
14 #include <mono/metadata/opcodes.h>
15 #include <mono/metadata/tabledefs.h>
16 #include <mono/metadata/reflection.h>
17 #include <mono/metadata/debug-helpers.h>
18 #include <mono/metadata/mono-endian.h>
19 #include <mono/metadata/metadata.h>
20 #include <mono/metadata/metadata-internals.h>
21 #include <mono/metadata/class-internals.h>
22 #include <mono/metadata/tokentype.h>
23 #include <mono/metadata/security-manager.h>
24 #include <mono/metadata/security-core-clr.h>
25 #include <mono/metadata/cil-coff.h>
26 #include <mono/metadata/attrdefs.h>
27 #include <mono/utils/strenc.h>
28 #include <mono/utils/mono-error-internals.h>
29 #include <mono/utils/bsearch.h>
34 #ifndef DISABLE_VERIFIER
36 TODO add fail fast mode
37 TODO add PE32+ support
38 TODO verify the entry point RVA and content.
39 TODO load_section_table and load_data_directories must take PE32+ into account
40 TODO add section relocation support
41 TODO verify the relocation table, since we really don't use, no need so far.
42 TODO do full PECOFF resources verification
43 TODO verify in the CLI header entry point and resources
44 TODO implement null token typeref validation
45 TODO verify table wide invariants for typedef (sorting and uniqueness)
46 TODO implement proper authenticode data directory validation
47 TODO verify properties that require multiple tables to be valid
48 FIXME use subtraction based bounds checking to avoid overflows
49 FIXME get rid of metadata_streams and other fields from VerifyContext
52 #ifdef MONO_VERIFIER_DEBUG
53 #define VERIFIER_DEBUG(code) do { code; } while (0)
55 #define VERIFIER_DEBUG(code)
58 #define INVALID_OFFSET ((guint32)-1)
59 #define INVALID_ADDRESS 0xffffffff
69 RESOURCE_TABLE_IDX = 2,
70 CERTIFICATE_TABLE_IDX = 4,
71 RELOCATION_TABLE_IDX = 5,
85 #define INVALID_TABLE (0xFF)
86 /*format: number of bits, number of tables, tables{n. tables} */
87 const static unsigned char coded_index_desc[] = {
88 #define TYPEDEF_OR_REF_DESC (0)
95 #define HAS_CONSTANT_DESC (TYPEDEF_OR_REF_DESC + 5)
102 #define HAS_CATTR_DESC (HAS_CONSTANT_DESC + 5)
110 MONO_TABLE_INTERFACEIMPL,
111 MONO_TABLE_MEMBERREF,
113 MONO_TABLE_DECLSECURITY,
116 MONO_TABLE_STANDALONESIG,
117 MONO_TABLE_MODULEREF,
120 MONO_TABLE_ASSEMBLYREF,
122 MONO_TABLE_EXPORTEDTYPE,
123 MONO_TABLE_MANIFESTRESOURCE,
124 MONO_TABLE_GENERICPARAM,
126 #define HAS_FIELD_MARSHAL_DESC (HAS_CATTR_DESC + 22)
132 #define HAS_DECL_SECURITY_DESC (HAS_FIELD_MARSHAL_DESC + 4)
139 #define MEMBERREF_PARENT_DESC (HAS_DECL_SECURITY_DESC + 5)
144 MONO_TABLE_MODULEREF,
148 #define HAS_SEMANTICS_DESC (MEMBERREF_PARENT_DESC + 7)
154 #define METHODDEF_OR_REF_DESC (HAS_SEMANTICS_DESC + 4)
158 MONO_TABLE_MEMBERREF,
160 #define MEMBER_FORWARDED_DESC (METHODDEF_OR_REF_DESC + 4)
166 #define IMPLEMENTATION_DESC (MEMBER_FORWARDED_DESC + 4)
170 MONO_TABLE_ASSEMBLYREF,
171 MONO_TABLE_EXPORTEDTYPE,
173 #define CATTR_TYPE_DESC (IMPLEMENTATION_DESC + 5)
179 MONO_TABLE_MEMBERREF,
182 #define RES_SCOPE_DESC (CATTR_TYPE_DESC + 7)
186 MONO_TABLE_MODULEREF,
187 MONO_TABLE_ASSEMBLYREF,
190 #define TYPE_OR_METHODDEF_DESC (RES_SCOPE_DESC + 6)
200 guint32 translated_offset;
212 guint32 rellocationsRVA;
213 guint16 numberOfRelocations;
228 gboolean report_error;
229 gboolean report_warning;
232 DataDirectory data_directories [16];
233 guint32 section_count;
234 SectionHeader *sections;
236 OffsetAndSize metadata_streams [5]; //offset from begin of the image
239 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception) \
241 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
242 vinfo->info.status = __status; \
243 vinfo->info.message = ( __msg); \
244 vinfo->exception_type = (__exception); \
245 (__ctx)->errors = g_slist_prepend ((__ctx)->errors, vinfo); \
248 #define ADD_WARNING(__ctx, __msg) \
250 if ((__ctx)->report_warning) { \
251 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_WARNING, MONO_EXCEPTION_INVALID_PROGRAM); \
252 (__ctx)->valid = 0; \
257 #define ADD_ERROR_NO_RETURN(__ctx, __msg) \
259 if ((__ctx)->report_error) \
260 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
261 (__ctx)->valid = 0; \
264 #define ADD_ERROR(__ctx, __msg) \
266 if ((__ctx)->report_error) \
267 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
268 (__ctx)->valid = 0; \
272 #define FAIL(__ctx, __msg) \
274 if ((__ctx)->report_error) \
275 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
276 (__ctx)->valid = 0; \
280 #define CHECK_STATE() do { if (!ctx.valid) goto cleanup; } while (0)
282 #define CHECK_ERROR() do { if (!ctx->valid) return; } while (0)
284 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
285 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
287 #if SIZEOF_VOID_P == 4
288 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
290 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
293 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
294 #define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
297 dword_align (const char *ptr)
299 #if SIZEOF_VOID_P == 8
300 return (const char *) (((guint64) (ptr + 3)) & ~3);
302 return (const char *) (((guint32) (ptr + 3)) & ~3);
307 add_from_mono_error (VerifyContext *ctx, MonoError *error)
309 if (mono_error_ok (error))
312 ADD_ERROR (ctx, g_strdup (mono_error_get_message (error)));
313 mono_error_cleanup (error);
317 pe_signature_offset (VerifyContext *ctx)
319 return read32 (ctx->data + 0x3c);
323 pe_header_offset (VerifyContext *ctx)
325 return read32 (ctx->data + 0x3c) + 4;
329 bounds_check_virtual_address (VerifyContext *ctx, guint32 rva, guint32 size)
333 if (rva + size < rva) //overflow
336 if (ctx->stage > STAGE_PE) {
337 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)ctx->image->image_info;
338 const int top = iinfo->cli_section_count;
339 MonoSectionTable *tables = iinfo->cli_section_tables;
342 for (i = 0; i < top; i++) {
343 guint32 base = tables->st_virtual_address;
344 guint32 end = base + tables->st_raw_data_size;
346 if (rva >= base && rva + size <= end)
349 /*if ((addr >= tables->st_virtual_address) &&
350 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
352 return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
362 for (i = 0; i < ctx->section_count; ++i) {
363 guint32 base = ctx->sections [i].baseRVA;
364 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
365 if (rva >= base && rva + size <= end)
372 bounds_check_datadir (DataDirectory *dir, guint32 offset, guint32 size)
374 if (dir->translated_offset > offset)
376 if (dir->size < size)
378 return offset + size <= dir->translated_offset + dir->size;
382 bounds_check_offset (OffsetAndSize *off, guint32 offset, guint32 size)
384 if (off->offset > offset)
387 if (off->size < size)
390 return offset + size <= off->offset + off->size;
394 translate_rva (VerifyContext *ctx, guint32 rva)
398 if (ctx->stage > STAGE_PE)
399 return mono_cli_rva_image_map (ctx->image, rva);
404 for (i = 0; i < ctx->section_count; ++i) {
405 guint32 base = ctx->sections [i].baseRVA;
406 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
407 if (rva >= base && rva <= end) {
408 guint32 res = (rva - base) + ctx->sections [i].baseOffset;
410 return res >= ctx->size ? INVALID_OFFSET : res;
414 return INVALID_OFFSET;
418 verify_msdos_header (VerifyContext *ctx)
422 ADD_ERROR (ctx, g_strdup ("Not enough space for the MS-DOS header"));
423 if (ctx->data [0] != 0x4d || ctx->data [1] != 0x5a)
424 ADD_ERROR (ctx, g_strdup ("Invalid MS-DOS watermark"));
425 lfanew = pe_signature_offset (ctx);
426 if (lfanew > ctx->size - 4)
427 ADD_ERROR (ctx, g_strdup ("MS-DOS lfanew offset points to outside of the file"));
431 verify_pe_header (VerifyContext *ctx)
433 guint32 offset = pe_signature_offset (ctx);
434 const char *pe_header = ctx->data + offset;
435 if (pe_header [0] != 'P' || pe_header [1] != 'E' ||pe_header [2] != 0 ||pe_header [3] != 0)
436 ADD_ERROR (ctx, g_strdup ("Invalid PE header watermark"));
440 if (offset > ctx->size - 20)
441 ADD_ERROR (ctx, g_strdup ("File with truncated pe header"));
442 if (read16 (pe_header) != 0x14c)
443 ADD_ERROR (ctx, g_strdup ("Invalid PE header Machine value"));
447 verify_pe_optional_header (VerifyContext *ctx)
449 guint32 offset = pe_header_offset (ctx);
450 guint32 header_size, file_alignment;
451 const char *pe_header = ctx->data + offset;
452 const char *pe_optional_header = pe_header + 20;
454 header_size = read16 (pe_header + 16);
457 if (header_size < 2) /*must be at least 2 or we won't be able to read magic*/
458 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
460 if (offset > ctx->size - header_size || header_size > ctx->size)
461 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
463 if (read16 (pe_optional_header) == 0x10b) {
464 if (header_size != 224)
465 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header size %d", header_size));
467 /* LAMESPEC MS plays around this value and ignore it during validation
468 if (read32 (pe_optional_header + 28) != 0x400000)
469 ADD_ERROR (ctx, g_strdup_printf ("Invalid Image base %x", read32 (pe_optional_header + 28)));*/
470 if (read32 (pe_optional_header + 32) != 0x2000)
471 ADD_ERROR (ctx, g_strdup_printf ("Invalid Section Aligmnent %x", read32 (pe_optional_header + 32)));
472 file_alignment = read32 (pe_optional_header + 36);
473 if (file_alignment != 0x200 && file_alignment != 0x1000)
474 ADD_ERROR (ctx, g_strdup_printf ("Invalid file Aligmnent %x", file_alignment));
475 /* All the junk in the middle is irrelevant, specially for mono. */
476 if (read32 (pe_optional_header + 92) > 0x10)
477 ADD_ERROR (ctx, g_strdup_printf ("Too many data directories %x", read32 (pe_optional_header + 92)));
479 if (read16 (pe_optional_header) == 0x20B)
480 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle PE32+"));
482 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header magic %d", read16 (pe_optional_header)));
487 load_section_table (VerifyContext *ctx)
490 SectionHeader *sections;
491 guint32 offset = pe_header_offset (ctx);
492 const char *ptr = ctx->data + offset;
493 guint16 num_sections = ctx->section_count = read16 (ptr + 2);
495 offset += 244;/*FIXME, this constant is different under PE32+*/
498 if (num_sections * 40 > ctx->size - offset)
499 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
501 sections = ctx->sections = g_new0 (SectionHeader, num_sections);
502 for (i = 0; i < num_sections; ++i) {
503 sections [i].size = read32 (ptr + 8);
504 sections [i].baseRVA = read32 (ptr + 12);
505 sections [i].baseOffset = read32 (ptr + 20);
506 sections [i].rellocationsRVA = read32 (ptr + 24);
507 sections [i].numberOfRelocations = read16 (ptr + 32);
511 ptr = ctx->data + offset; /*reset it to the beggining*/
512 for (i = 0; i < num_sections; ++i) {
513 guint32 raw_size, flags;
514 if (sections [i].baseOffset == 0)
515 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with intialized data only"));
516 if (sections [i].baseOffset >= ctx->size)
517 ADD_ERROR (ctx, g_strdup_printf ("Invalid PointerToRawData %x points beyond EOF", sections [i].baseOffset));
518 if (sections [i].size > ctx->size - sections [i].baseOffset)
519 ADD_ERROR (ctx, g_strdup ("Invalid VirtualSize points beyond EOF"));
521 raw_size = read32 (ptr + 16);
522 if (raw_size < sections [i].size)
523 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with SizeOfRawData < VirtualSize"));
525 if (raw_size > ctx->size - sections [i].baseOffset)
526 ADD_ERROR (ctx, g_strdup_printf ("Invalid SizeOfRawData %x points beyond EOF", raw_size));
528 if (sections [i].rellocationsRVA || sections [i].numberOfRelocations)
529 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't handle section relocation"));
531 flags = read32 (ptr + 36);
532 /*TODO 0xFE0000E0 is all flags from cil-coff.h OR'd. Make it a less magical number*/
533 if (flags == 0 || (flags & ~0xFE0000E0) != 0)
534 ADD_ERROR (ctx, g_strdup_printf ("Invalid section flags %x", flags));
541 is_valid_data_directory (int i)
543 /*LAMESPEC 4 == certificate 6 == debug, MS uses both*/
544 return i == 1 || i == 2 || i == 5 || i == 12 || i == 14 || i == 4 || i == 6;
548 load_data_directories (VerifyContext *ctx)
550 guint32 offset = pe_header_offset (ctx) + 116; /*FIXME, this constant is different under PE32+*/
551 const char *ptr = ctx->data + offset;
554 for (i = 0; i < 16; ++i) {
555 guint32 rva = read32 (ptr);
556 guint32 size = read32 (ptr + 4);
558 /*LAMESPEC the authenticode data directory format is different. We don't support CAS, so lets ignore for now.*/
559 if (i == CERTIFICATE_TABLE_IDX) {
563 if ((rva != 0 || size != 0) && !is_valid_data_directory (i))
564 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d", i));
566 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
567 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d rva/size pair %x/%x", i, rva, size));
569 ctx->data_directories [i].rva = rva;
570 ctx->data_directories [i].size = size;
571 ctx->data_directories [i].translated_offset = translate_rva (ctx, rva);
577 #define SIZE_OF_MSCOREE (sizeof ("mscoree.dll"))
579 #define SIZE_OF_CORMAIN (sizeof ("_CorExeMain"))
582 verify_hint_name_table (VerifyContext *ctx, guint32 import_rva, const char *table_name)
585 guint32 hint_table_rva;
587 import_rva = translate_rva (ctx, import_rva);
588 g_assert (import_rva != INVALID_OFFSET);
590 hint_table_rva = read32 (ctx->data + import_rva);
591 if (!bounds_check_virtual_address (ctx, hint_table_rva, SIZE_OF_CORMAIN + 2))
592 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint/Name rva %d for %s", hint_table_rva, table_name));
594 hint_table_rva = translate_rva (ctx, hint_table_rva);
595 g_assert (hint_table_rva != INVALID_OFFSET);
596 ptr = ctx->data + hint_table_rva + 2;
598 if (memcmp ("_CorExeMain", ptr, SIZE_OF_CORMAIN) && memcmp ("_CorDllMain", ptr, SIZE_OF_CORMAIN)) {
599 char name[SIZE_OF_CORMAIN];
600 memcpy (name, ptr, SIZE_OF_CORMAIN);
601 name [SIZE_OF_CORMAIN - 1] = 0;
602 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint / Name: '%s'", name));
607 verify_import_table (VerifyContext *ctx)
609 DataDirectory it = ctx->data_directories [IMPORT_TABLE_IDX];
610 guint32 offset = it.translated_offset;
611 const char *ptr = ctx->data + offset;
612 guint32 name_rva, ilt_rva, iat_rva;
614 g_assert (offset != INVALID_OFFSET);
617 ADD_ERROR (ctx, g_strdup_printf ("Import table size %d is smaller than 40", it.size));
619 ilt_rva = read32 (ptr);
620 if (ilt_rva && !bounds_check_virtual_address (ctx, ilt_rva, 8))
621 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Lookup Table rva %x", ilt_rva));
623 name_rva = read32 (ptr + 12);
624 if (name_rva && !bounds_check_virtual_address (ctx, name_rva, SIZE_OF_MSCOREE))
625 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name rva %x", name_rva));
627 iat_rva = read32 (ptr + 16);
629 if (!bounds_check_virtual_address (ctx, iat_rva, 8))
630 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Address Table rva %x", iat_rva));
632 if (iat_rva != ctx->data_directories [IAT_IDX].rva)
633 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));
637 name_rva = translate_rva (ctx, name_rva);
638 g_assert (name_rva != INVALID_OFFSET);
639 ptr = ctx->data + name_rva;
641 if (memcmp ("mscoree.dll", ptr, SIZE_OF_MSCOREE)) {
642 char name[SIZE_OF_MSCOREE];
643 memcpy (name, ptr, SIZE_OF_MSCOREE);
644 name [SIZE_OF_MSCOREE - 1] = 0;
645 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name: '%s'", name));
650 verify_hint_name_table (ctx, ilt_rva, "Import Lookup Table");
655 verify_hint_name_table (ctx, iat_rva, "Import Address Table");
659 verify_resources_table (VerifyContext *ctx)
661 DataDirectory it = ctx->data_directories [RESOURCE_TABLE_IDX];
663 guint16 named_entries, id_entries;
670 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));
672 offset = it.translated_offset;
673 ptr = ctx->data + offset;
675 g_assert (offset != INVALID_OFFSET);
677 named_entries = read16 (ptr + 12);
678 id_entries = read16 (ptr + 14);
680 if ((named_entries + id_entries) * 8 + 16 > it.size)
681 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));
683 /* XXX at least one unmanaged resource is added due to a call to AssemblyBuilder::DefineVersionInfoResource ()
684 if (named_entries || id_entries)
685 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support full verification of PECOFF resources"));
689 /*----------nothing from here on can use data_directory---*/
692 get_data_dir (VerifyContext *ctx, int idx)
694 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)ctx->image->image_info;
695 MonoPEDirEntry *entry= &iinfo->cli_header.datadir.pe_export_table;
699 res.rva = entry->rva;
700 res.size = entry->size;
701 res.translated_offset = translate_rva (ctx, res.rva);
706 verify_cli_header (VerifyContext *ctx)
708 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
714 ADD_ERROR (ctx, g_strdup_printf ("CLI header missing"));
717 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size in data directory %d must be 72", it.size));
719 offset = it.translated_offset;
720 ptr = ctx->data + offset;
722 g_assert (offset != INVALID_OFFSET);
724 if (read16 (ptr) != 72)
725 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size %d must be 72", read16 (ptr)));
727 if (!bounds_check_virtual_address (ctx, read32 (ptr + 8), read32 (ptr + 12)))
728 ADD_ERROR (ctx, g_strdup_printf ("Invalid medatata section rva/size pair %x/%x", read32 (ptr + 8), read32 (ptr + 12)));
731 if (!read32 (ptr + 8) || !read32 (ptr + 12))
732 ADD_ERROR (ctx, g_strdup_printf ("Missing medatata section in the CLI header"));
734 if ((read32 (ptr + 16) & ~0x0003000B) != 0)
735 ADD_ERROR (ctx, g_strdup_printf ("Invalid CLI header flags"));
738 for (i = 0; i < 6; ++i) {
739 guint32 rva = read32 (ptr);
740 guint32 size = read32 (ptr + 4);
742 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
743 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli section %i rva/size pair %x/%x", i, rva, size));
748 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't support cli header section %d", i));
753 pad4 (guint32 offset)
755 if (offset & 0x3) //pad to the next 4 byte boundary
756 offset = (offset & ~0x3) + 4;
761 verify_metadata_header (VerifyContext *ctx)
764 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
765 guint32 offset, section_count;
768 offset = it.translated_offset;
769 ptr = ctx->data + offset;
770 g_assert (offset != INVALID_OFFSET);
772 //build a directory entry for the metadata root
774 it.rva = read32 (ptr);
776 it.size = read32 (ptr);
777 it.translated_offset = offset = translate_rva (ctx, it.rva);
779 ptr = ctx->data + offset;
780 g_assert (offset != INVALID_OFFSET);
783 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small %d (at least 20 bytes required for initial decoding)", it.size));
785 if (read32 (ptr) != 0x424A5342)
786 ADD_ERROR (ctx, g_strdup_printf ("Invalid metadata signature, expected 0x424A5342 but got %08x", read32 (ptr)));
788 offset = pad4 (offset + 16 + read32 (ptr + 12));
790 if (!bounds_check_datadir (&it, offset, 4))
791 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));
793 ptr = ctx->data + offset; //move to streams header
795 section_count = read16 (ptr + 2);
796 if (section_count < 2)
797 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section must have at least 2 streams (#~ and #GUID)"));
802 for (i = 0; i < section_count; ++i) {
803 guint32 stream_off, stream_size;
804 int string_size, stream_idx;
806 if (!bounds_check_datadir (&it, offset, 8))
807 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));
809 stream_off = it.translated_offset + read32 (ptr);
810 stream_size = read32 (ptr + 4);
812 if (!bounds_check_datadir (&it, stream_off, stream_size))
813 ADD_ERROR (ctx, g_strdup_printf ("Invalid stream header %d offset/size pair %x/%x", 0, stream_off, stream_size));
818 for (string_size = 0; string_size < 32; ++string_size) {
819 if (!bounds_check_datadir (&it, offset++, 1))
820 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small to decode stream header %d name", i));
821 if (!ptr [string_size])
825 if (ptr [string_size])
826 ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d name larger than 32 bytes", i));
828 if (!strncmp ("#Strings", ptr, 9))
829 stream_idx = STRINGS_STREAM;
830 else if (!strncmp ("#US", ptr, 4))
831 stream_idx = USER_STRINGS_STREAM;
832 else if (!strncmp ("#Blob", ptr, 6))
833 stream_idx = BLOB_STREAM;
834 else if (!strncmp ("#GUID", ptr, 6))
835 stream_idx = GUID_STREAM;
836 else if (!strncmp ("#~", ptr, 3))
837 stream_idx = TILDE_STREAM;
839 ADD_WARNING (ctx, g_strdup_printf ("Metadata stream header %d invalid name %s", i, ptr));
840 offset = pad4 (offset);
841 ptr = ctx->data + offset;
845 if (ctx->metadata_streams [stream_idx].offset != 0)
846 ADD_ERROR (ctx, g_strdup_printf ("Duplicated metadata stream header %s", ptr));
848 ctx->metadata_streams [stream_idx].offset = stream_off;
849 ctx->metadata_streams [stream_idx].size = stream_size;
851 offset = pad4 (offset);
852 ptr = ctx->data + offset;
855 if (!ctx->metadata_streams [TILDE_STREAM].size)
856 ADD_ERROR (ctx, g_strdup_printf ("Metadata #~ stream missing"));
857 if (!ctx->metadata_streams [GUID_STREAM].size)
858 ADD_ERROR (ctx, g_strdup_printf ("Metadata guid stream missing"));
862 verify_tables_schema (VerifyContext *ctx)
864 OffsetAndSize tables_area = ctx->metadata_streams [TILDE_STREAM];
865 unsigned offset = tables_area.offset;
866 const char *ptr = ctx->data + offset;
867 guint64 valid_tables;
871 if (tables_area.size < 24)
872 ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for initial decoding (requires 24 bytes)", tables_area.size));
874 if (ptr [4] != 2 && ptr [4] != 1)
875 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata major version %d, expected 2", ptr [4]));
877 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata minor version %d, expected 0", ptr [5]));
879 if ((ptr [6] & ~0x7) != 0)
880 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]));
882 valid_tables = read64 (ptr + 8);
884 for (i = 0; i < 64; ++i) {
885 if (!(valid_tables & ((guint64)1 << i)))
888 /*MS Extensions: 0x3 0x5 0x7 0x13 0x16
889 Unused: 0x1E 0x1F 0x2D-0x3F
890 We don't care about the MS extensions.*/
891 if (i == 0x3 || i == 0x5 || i == 0x7 || i == 0x13 || i == 0x16)
892 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support MS specific table %x", i));
893 if (i == 0x1E || i == 0x1F || i >= 0x2D)
894 ADD_ERROR (ctx, g_strdup_printf ("Invalid table %x", i));
898 if (tables_area.size < 24 + count * 4)
899 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));
902 for (i = 0; i < 64; ++i) {
903 if (valid_tables & ((guint64)1 << i)) {
904 guint32 row_count = read32 (ptr);
905 if (row_count > (1 << 24) - 1)
906 ADD_ERROR (ctx, g_strdup_printf ("Invalid Table %d row count: %d. Mono only supports 16777215 rows", i, row_count));
912 /*----------nothing from here on can use data_directory or metadata_streams ---*/
915 get_col_offset (VerifyContext *ctx, int table, int column)
917 guint32 bitfield = ctx->image->tables [table].size_bitfield;
921 offset += mono_metadata_table_size (bitfield, column);
927 get_col_size (VerifyContext *ctx, int table, int column)
929 return mono_metadata_table_size (ctx->image->tables [table].size_bitfield, column);
933 get_metadata_stream (VerifyContext *ctx, MonoStreamHeader *header)
936 res.offset = header->data - ctx->data;
937 res.size = header->size;
943 is_valid_string_full_with_image (MonoImage *image, guint32 offset, gboolean allow_empty)
945 guint32 heap_offset = (char*)image->heap_strings.data - image->raw_data;
946 guint32 heap_size = image->heap_strings.size;
949 const char *data = image->raw_data + heap_offset;
951 if (offset >= heap_size)
953 if (CHECK_ADDP_OVERFLOW_UN (data, offset))
956 if (!mono_utf8_validate_and_len_with_bounds (data + offset, heap_size - offset, &length, NULL))
958 return allow_empty || length > 0;
963 is_valid_string_full (VerifyContext *ctx, guint32 offset, gboolean allow_empty)
965 return is_valid_string_full_with_image (ctx->image, offset, allow_empty);
969 is_valid_string (VerifyContext *ctx, guint32 offset)
971 return is_valid_string_full (ctx, offset, TRUE);
975 is_valid_non_empty_string (VerifyContext *ctx, guint32 offset)
977 return is_valid_string_full (ctx, offset, FALSE);
981 is_valid_guid (VerifyContext *ctx, guint32 offset)
983 OffsetAndSize guids = get_metadata_stream (ctx, &ctx->image->heap_guid);
984 return guids.size >= 8 && guids.size - 8 >= offset;
988 get_coded_index_token (int token_kind, guint32 coded_token)
990 guint32 bits = coded_index_desc [token_kind];
991 return coded_token >> bits;
995 get_coded_index_table (int kind, guint32 coded_token)
997 guint32 idx, bits = coded_index_desc [kind];
999 idx = coded_token & ((1 << bits) - 1);
1000 return coded_index_desc [kind + idx];
1004 make_coded_token (int kind, guint32 table, guint32 table_idx)
1006 guint32 bits = coded_index_desc [kind++];
1007 guint32 tables = coded_index_desc [kind++];
1009 for (i = 0; i < tables; ++i) {
1010 if (coded_index_desc [kind++] == table)
1011 return ((table_idx + 1) << bits) | i;
1013 g_assert_not_reached ();
1018 is_valid_coded_index_with_image (MonoImage *image, int token_kind, guint32 coded_token)
1020 guint32 bits = coded_index_desc [token_kind++];
1021 guint32 table_count = coded_index_desc [token_kind++];
1022 guint32 table = coded_token & ((1 << bits) - 1);
1023 guint32 token = coded_token >> bits;
1025 if (table >= table_count)
1028 /*token_kind points to the first table idx*/
1029 table = coded_index_desc [token_kind + table];
1031 if (table == INVALID_TABLE)
1033 return token <= image->tables [table].rows;
1037 is_valid_coded_index (VerifyContext *ctx, int token_kind, guint32 coded_token)
1039 return is_valid_coded_index_with_image (ctx->image, token_kind, coded_token);
1046 MonoTableInfo *table;
1050 token_locator (const void *a, const void *b)
1052 RowLocator *loc = (RowLocator *)a;
1053 unsigned const char *row = (unsigned const char *)b;
1054 guint32 token = loc->col_size == 2 ? read16 (row + loc->col_offset) : read32 (row + loc->col_offset);
1056 VERIFIER_DEBUG ( printf ("\tfound token %x at idx %d\n", token, ((const char*)row - loc->table->base) / loc->table->row_size) );
1057 return (int)loc->token - (int)token;
1061 search_sorted_table (VerifyContext *ctx, int table, int column, guint32 coded_token)
1063 MonoTableInfo *tinfo = &ctx->image->tables [table];
1065 const char *res, *base;
1066 locator.token = coded_token;
1067 locator.col_offset = get_col_offset (ctx, table, column);
1068 locator.col_size = get_col_size (ctx, table, column);
1069 locator.table = tinfo;
1073 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) );
1074 res = (const char *)mono_binary_search (&locator, base, tinfo->rows, tinfo->row_size, token_locator);
1078 return (res - base) / tinfo->row_size;
1081 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1083 get_string_ptr (VerifyContext *ctx, guint offset)
1085 return ctx->image->heap_strings.data + offset;
1088 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1090 string_cmp (VerifyContext *ctx, const char *str, guint offset)
1093 return strcmp (str, "");
1095 return strcmp (str, get_string_ptr (ctx, offset));
1099 mono_verifier_is_corlib (MonoImage *image)
1101 gboolean trusted_location = !mono_security_core_clr_enabled () ?
1102 TRUE : mono_security_core_clr_is_platform_image (image);
1104 return trusted_location && image->module_name && !strcmp ("mscorlib.dll", image->module_name);
1108 typedef_is_system_object (VerifyContext *ctx, guint32 *data)
1110 return mono_verifier_is_corlib (ctx->image) && !string_cmp (ctx, "System", data [MONO_TYPEDEF_NAMESPACE]) && !string_cmp (ctx, "Object", data [MONO_TYPEDEF_NAME]);
1114 decode_value (const char *_ptr, unsigned available, unsigned *value, unsigned *size)
1117 const unsigned char *ptr = (const unsigned char *)_ptr;
1125 if ((b & 0x80) == 0) {
1128 } else if ((b & 0x40) == 0) {
1132 *value = ((b & 0x3f) << 8 | ptr [1]);
1137 *value = ((b & 0x1f) << 24) |
1147 decode_signature_header (VerifyContext *ctx, guint32 offset, guint32 *size, const char **first_byte)
1149 MonoStreamHeader blob = ctx->image->heap_blob;
1150 guint32 value, enc_size;
1152 if (offset >= blob.size)
1155 if (!decode_value (blob.data + offset, blob.size - offset, &value, &enc_size))
1158 if (CHECK_ADD4_OVERFLOW_UN (offset, enc_size))
1163 if (ADD_IS_GREATER_OR_OVF (offset, value, blob.size))
1167 *first_byte = blob.data + offset;
1172 safe_read (const char **_ptr, const char *limit, unsigned *dest, int size)
1174 const char *ptr = *_ptr;
1175 if (ptr + size > limit)
1179 *dest = *((guint8*)ptr);
1183 *dest = read16 (ptr);
1187 *dest = read32 (ptr);
1196 safe_read_compressed_int (const char **_ptr, const char *limit, unsigned *dest)
1199 const char *ptr = *_ptr;
1200 gboolean res = decode_value (ptr, limit - ptr, dest, &size);
1205 #define safe_read8(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 1)
1206 #define safe_read_cint(VAR, PTR, LIMIT) safe_read_compressed_int (&PTR, LIMIT, &VAR)
1207 #define safe_read16(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 2)
1208 #define safe_read32(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 4)
1211 parse_type (VerifyContext *ctx, const char **_ptr, const char *end);
1214 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged);
1217 parse_custom_mods (VerifyContext *ctx, const char **_ptr, const char *end)
1219 const char *ptr = *_ptr;
1224 if (!safe_read8 (type, ptr, end))
1225 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the type"));
1227 if (type != MONO_TYPE_CMOD_REQD && type != MONO_TYPE_CMOD_OPT) {
1232 if (!safe_read_cint (token, ptr, end))
1233 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the token"));
1235 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token) || !get_coded_index_token (TYPEDEF_OR_REF_DESC, token))
1236 FAIL (ctx, g_strdup_printf ("CustomMod: invalid TypeDefOrRef token %x", token));
1244 parse_array_shape (VerifyContext *ctx, const char **_ptr, const char *end)
1246 const char *ptr = *_ptr;
1248 unsigned size, num, i;
1250 if (!safe_read8 (val, ptr, end))
1251 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for Rank"));
1254 FAIL (ctx, g_strdup ("ArrayShape: Invalid shape with zero Rank"));
1256 if (!safe_read_cint (size, ptr, end))
1257 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumSizes"));
1259 for (i = 0; i < size; ++i) {
1260 if (!safe_read_cint (num, ptr, end))
1261 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for Size of rank %d", i + 1));
1264 if (!safe_read_cint (size, ptr, end))
1265 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumLoBounds"));
1267 for (i = 0; i < size; ++i) {
1268 if (!safe_read_cint (num, ptr, end))
1269 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for LoBound of rank %d", i + 1));
1277 parse_generic_inst (VerifyContext *ctx, const char **_ptr, const char *end)
1279 const char *ptr = *_ptr;
1281 unsigned count, token, i;
1283 if (!safe_read8 (type, ptr, end))
1284 FAIL (ctx, g_strdup ("GenericInst: Not enough room for kind"));
1286 if (type != MONO_TYPE_CLASS && type != MONO_TYPE_VALUETYPE)
1287 FAIL (ctx, g_strdup_printf ("GenericInst: Invalid GenericInst kind %x\n", type));
1289 if (!safe_read_cint (token, ptr, end))
1290 FAIL (ctx, g_strdup ("GenericInst: Not enough room for type token"));
1292 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token) || !get_coded_index_token (TYPEDEF_OR_REF_DESC, token))
1293 FAIL (ctx, g_strdup_printf ("GenericInst: invalid TypeDefOrRef token %x", token));
1296 if (mono_metadata_token_index (ctx->token) == get_coded_index_token (TYPEDEF_OR_REF_DESC, token) &&
1297 mono_metadata_token_table (ctx->token) == get_coded_index_table (TYPEDEF_OR_REF_DESC, token))
1298 FAIL (ctx, g_strdup_printf ("Type: Recurside generic instance specification (%x). A type signature can't reference itself", ctx->token));
1301 if (!safe_read_cint (count, ptr, end))
1302 FAIL (ctx, g_strdup ("GenericInst: Not enough room for argument count"));
1305 FAIL (ctx, g_strdup ("GenericInst: Zero arguments generic instance"));
1307 for (i = 0; i < count; ++i) {
1308 if (!parse_custom_mods (ctx, &ptr, end))
1309 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1311 if (!parse_type (ctx, &ptr, end))
1312 FAIL (ctx, g_strdup_printf ("GenericInst: invalid generic argument %d", i + 1));
1319 parse_type (VerifyContext *ctx, const char **_ptr, const char *end)
1321 const char *ptr = *_ptr;
1325 if (!safe_read8 (type, ptr, end))
1326 FAIL (ctx, g_strdup ("Type: Not enough room for the type"));
1328 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_PTR) ||
1329 (type >= MONO_TYPE_VALUETYPE && type <= MONO_TYPE_GENERICINST) ||
1330 (type >= MONO_TYPE_I && type <= MONO_TYPE_U) ||
1331 (type >= MONO_TYPE_FNPTR && type <= MONO_TYPE_MVAR)))
1332 FAIL (ctx, g_strdup_printf ("Type: Invalid type kind %x\n", type));
1336 if (!parse_custom_mods (ctx, &ptr, end))
1337 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1339 if (!safe_read8 (type, ptr, end))
1340 FAIL (ctx, g_strdup ("Type: Not enough room to parse the pointer type"));
1342 if (type != MONO_TYPE_VOID) {
1344 if (!parse_type (ctx, &ptr, end))
1345 FAIL (ctx, g_strdup ("Type: Could not parse pointer type"));
1349 case MONO_TYPE_VALUETYPE:
1350 case MONO_TYPE_CLASS:
1351 if (!safe_read_cint (token, ptr, end))
1352 FAIL (ctx, g_strdup ("Type: Not enough room for the type token"));
1354 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token) || !get_coded_index_token (TYPEDEF_OR_REF_DESC, token))
1355 FAIL (ctx, g_strdup_printf ("Type: invalid TypeDefOrRef token %x", token));
1357 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, token))
1358 FAIL (ctx, g_strdup_printf ("Type: zero TypeDefOrRef token %x", token));
1360 if (mono_metadata_token_index (ctx->token) == get_coded_index_token (TYPEDEF_OR_REF_DESC, token) &&
1361 mono_metadata_token_table (ctx->token) == get_coded_index_table (TYPEDEF_OR_REF_DESC, token))
1362 FAIL (ctx, g_strdup_printf ("Type: Recursive type specification (%x). A type signature can't reference itself", ctx->token));
1367 case MONO_TYPE_MVAR:
1368 if (!safe_read_cint (token, ptr, end))
1369 FAIL (ctx, g_strdup ("Type: Not enough room for to decode generic argument number"));
1372 case MONO_TYPE_ARRAY:
1373 if (!parse_type (ctx, &ptr, end))
1374 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1375 if (!parse_array_shape (ctx, &ptr, end))
1376 FAIL (ctx, g_strdup ("Type: Could not parse array shape"));
1379 case MONO_TYPE_GENERICINST:
1380 if (!parse_generic_inst (ctx, &ptr, end))
1381 FAIL (ctx, g_strdup ("Type: Could not parse generic inst"));
1384 case MONO_TYPE_FNPTR:
1385 if (!parse_method_signature (ctx, &ptr, end, TRUE, TRUE))
1386 FAIL (ctx, g_strdup ("Type: Could not parse method pointer signature"));
1389 case MONO_TYPE_SZARRAY:
1390 if (!parse_custom_mods (ctx, &ptr, end))
1391 FAIL (ctx, g_strdup ("Type: Failed to parse array element custom attr"));
1392 if (!parse_type (ctx, &ptr, end))
1393 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1401 parse_return_type (VerifyContext *ctx, const char **_ptr, const char *end)
1406 if (!parse_custom_mods (ctx, _ptr, end))
1410 if (!safe_read8 (type, ptr, end))
1411 FAIL (ctx, g_strdup ("ReturnType: Not enough room for the type"));
1413 if (type == MONO_TYPE_VOID || type == MONO_TYPE_TYPEDBYREF) {
1418 //it's a byref, update the cursor ptr
1419 if (type == MONO_TYPE_BYREF)
1422 return parse_type (ctx, _ptr, end);
1426 parse_param (VerifyContext *ctx, const char **_ptr, const char *end)
1431 if (!parse_custom_mods (ctx, _ptr, end))
1435 if (!safe_read8 (type, ptr, end))
1436 FAIL (ctx, g_strdup ("Param: Not enough room for the type"));
1438 if (type == MONO_TYPE_TYPEDBYREF) {
1443 //it's a byref, update the cursor ptr
1444 if (type == MONO_TYPE_BYREF) {
1446 if (!parse_custom_mods (ctx, _ptr, end))
1450 return parse_type (ctx, _ptr, end);
1454 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged)
1457 unsigned param_count = 0, gparam_count = 0, type = 0, i;
1458 const char *ptr = *_ptr;
1459 gboolean saw_sentinel = FALSE;
1461 if (!safe_read8 (cconv, ptr, end))
1462 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the call conv"));
1465 FAIL (ctx, g_strdup ("MethodSig: CallConv has 0x80 set"));
1467 if (allow_unmanaged) {
1468 if ((cconv & 0x0F) > MONO_CALL_VARARG)
1469 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not valid, it's %x", cconv & 0x0F));
1470 } else if ((cconv & 0x0F) != MONO_CALL_DEFAULT && (cconv & 0x0F) != MONO_CALL_VARARG)
1471 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not Default or Vararg, it's %x", cconv & 0x0F));
1473 if ((cconv & 0x10) && !safe_read_cint (gparam_count, ptr, end))
1474 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the generic param count"));
1476 if ((cconv & 0x10) && gparam_count == 0)
1477 FAIL (ctx, g_strdup ("MethodSig: Signature with generics but zero arity"));
1479 if (allow_unmanaged && (cconv & 0x10))
1480 FAIL (ctx, g_strdup ("MethodSig: Standalone signature with generic params"));
1482 if (!safe_read_cint (param_count, ptr, end))
1483 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the param count"));
1485 if (!parse_return_type (ctx, &ptr, end))
1486 FAIL (ctx, g_strdup ("MethodSig: Error parsing return type"));
1488 for (i = 0; i < param_count; ++i) {
1489 if (allow_sentinel) {
1490 if (!safe_read8 (type, ptr, end))
1491 FAIL (ctx, g_strdup_printf ("MethodSig: Not enough room for param %d type", i));
1493 if (type == MONO_TYPE_SENTINEL) {
1494 if ((cconv & 0x0F) != MONO_CALL_VARARG)
1495 FAIL (ctx, g_strdup ("MethodSig: Found sentinel but signature is not vararg"));
1498 FAIL (ctx, g_strdup ("MethodSig: More than one sentinel type"));
1500 saw_sentinel = TRUE;
1506 if (!parse_param (ctx, &ptr, end))
1507 FAIL (ctx, g_strdup_printf ("MethodSig: Error parsing arg %d", i));
1515 parse_property_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1519 unsigned param_count = 0, i;
1520 const char *ptr = *_ptr;
1522 if (!safe_read8 (sig, ptr, end))
1523 FAIL (ctx, g_strdup ("PropertySig: Not enough room for signature"));
1525 if (sig != 0x08 && sig != 0x28)
1526 FAIL (ctx, g_strdup_printf ("PropertySig: Signature is not 0x28 or 0x08: %x", sig));
1528 if (!safe_read_cint (param_count, ptr, end))
1529 FAIL (ctx, g_strdup ("PropertySig: Not enough room for the param count"));
1531 if (!parse_custom_mods (ctx, &ptr, end))
1534 if (!safe_read8 (type, ptr, end))
1535 FAIL (ctx, g_strdup ("PropertySig: Not enough room for the type"));
1537 //check if it's a byref. safe_read8 did update ptr, so we rollback if it's not a byref
1538 if (type != MONO_TYPE_BYREF)
1541 if (!parse_type (ctx, &ptr, end))
1542 FAIL (ctx, g_strdup ("PropertySig: Could not parse property type"));
1544 for (i = 0; i < param_count; ++i) {
1545 if (!parse_custom_mods (ctx, &ptr, end))
1546 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1547 if (!parse_type (ctx, &ptr, end))
1548 FAIL (ctx, g_strdup_printf ("PropertySig: Error parsing arg %d", i));
1556 parse_field (VerifyContext *ctx, const char **_ptr, const char *end)
1558 const char *ptr = *_ptr;
1559 unsigned signature = 0;
1561 if (!safe_read8 (signature, ptr, end))
1562 FAIL (ctx, g_strdup ("Field: Not enough room for field signature"));
1564 if (signature != 0x06)
1565 FAIL (ctx, g_strdup_printf ("Field: Invalid signature 0x%x, must be 6", signature));
1567 if (!parse_custom_mods (ctx, &ptr, end))
1570 if (safe_read8 (signature, ptr, end)) {
1571 if (signature != MONO_TYPE_BYREF)
1576 return parse_type (ctx, _ptr, end);
1580 parse_locals_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1583 unsigned locals_count = 0, i;
1584 const char *ptr = *_ptr;
1586 if (!safe_read8 (sig, ptr, end))
1587 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for signature"));
1590 FAIL (ctx, g_strdup_printf ("LocalsSig: Signature is not 0x28 or 0x08: %x", sig));
1592 if (!safe_read_cint (locals_count, ptr, end))
1593 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for the param count"));
1595 /* LAMEIMPL: MS sometimes generates empty local signatures and its verifier is ok with.
1596 if (locals_count == 0)
1597 FAIL (ctx, g_strdup ("LocalsSig: Signature with zero locals"));
1600 for (i = 0; i < locals_count; ++i) {
1601 if (!safe_read8 (sig, ptr, end))
1602 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1604 while (sig == MONO_TYPE_CMOD_REQD || sig == MONO_TYPE_CMOD_OPT || sig == MONO_TYPE_PINNED) {
1605 if (sig != MONO_TYPE_PINNED && !parse_custom_mods (ctx, &ptr, end))
1606 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1607 if (!safe_read8 (sig, ptr, end))
1608 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1611 if (sig == MONO_TYPE_BYREF) {
1612 if (!safe_read8 (sig, ptr, end))
1613 FAIL (ctx, g_strdup_printf ("Type: Not enough room for byref type for local %d", i));
1614 if (sig == MONO_TYPE_TYPEDBYREF)
1615 FAIL (ctx, g_strdup_printf ("Type: Invalid type typedref& for local %d", i));
1618 if (sig == MONO_TYPE_TYPEDBYREF)
1623 if (!parse_type (ctx, &ptr, end))
1624 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1632 is_valid_field_signature (VerifyContext *ctx, guint32 offset)
1635 unsigned signature = 0;
1636 const char *ptr = NULL, *end;
1638 if (!decode_signature_header (ctx, offset, &size, &ptr))
1639 FAIL (ctx, g_strdup ("FieldSig: Could not decode signature header"));
1642 if (!safe_read8 (signature, ptr, end))
1643 FAIL (ctx, g_strdup ("FieldSig: Not enough room for the signature"));
1646 FAIL (ctx, g_strdup_printf ("FieldSig: Invalid signature %x", signature));
1649 return parse_field (ctx, &ptr, end);
1653 is_valid_method_signature (VerifyContext *ctx, guint32 offset)
1656 const char *ptr = NULL, *end;
1658 if (!decode_signature_header (ctx, offset, &size, &ptr))
1659 FAIL (ctx, g_strdup ("MethodSig: Could not decode signature header"));
1662 return parse_method_signature (ctx, &ptr, end, FALSE, FALSE);
1666 is_valid_memberref_method_signature (VerifyContext *ctx, guint32 offset)
1669 const char *ptr = NULL, *end;
1671 if (!decode_signature_header (ctx, offset, &size, &ptr))
1672 FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
1675 return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1680 is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
1683 unsigned signature = 0;
1684 const char *ptr = NULL, *end;
1686 if (!decode_signature_header (ctx, offset, &size, &ptr))
1687 FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
1690 if (!safe_read8 (signature, ptr, end))
1691 FAIL (ctx, g_strdup ("MemberRefSig: Not enough room for the call conv"));
1694 if (signature == 0x06)
1695 return parse_field (ctx, &ptr, end);
1697 return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1701 is_valid_cattr_blob (VerifyContext *ctx, guint32 offset)
1704 unsigned prolog = 0;
1705 const char *ptr = NULL, *end;
1710 if (!decode_signature_header (ctx, offset, &size, &ptr))
1711 FAIL (ctx, g_strdup ("CustomAttribute: Could not decode signature header"));
1714 if (!safe_read16 (prolog, ptr, end))
1715 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1718 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1724 is_valid_cattr_type (MonoType *type)
1728 if (type->type == MONO_TYPE_OBJECT || (type->type >= MONO_TYPE_BOOLEAN && type->type <= MONO_TYPE_STRING))
1731 if (type->type == MONO_TYPE_VALUETYPE) {
1732 klass = mono_class_from_mono_type (type);
1733 return klass && klass->enumtype;
1736 if (type->type == MONO_TYPE_CLASS)
1737 return mono_class_from_mono_type (type) == mono_defaults.systemtype_class;
1743 is_valid_ser_string_full (VerifyContext *ctx, const char **str_start, guint32 *str_len, const char **_ptr, const char *end)
1746 const char *ptr = *_ptr;
1752 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string size"));
1755 if (*ptr == (char)0xFF) {
1760 if (!safe_read_cint (size, ptr, end))
1761 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string size"));
1763 if (ADDP_IS_GREATER_OR_OVF (ptr, size, end))
1764 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string"));
1774 is_valid_ser_string (VerifyContext *ctx, const char **_ptr, const char *end)
1776 const char *dummy_str;
1778 return is_valid_ser_string_full (ctx, &dummy_str, &dummy_int, _ptr, end);
1782 get_enum_by_encoded_name (VerifyContext *ctx, const char **_ptr, const char *end)
1786 const char *str_start = NULL;
1787 const char *ptr = *_ptr;
1789 guint32 str_len = 0;
1791 if (!is_valid_ser_string_full (ctx, &str_start, &str_len, &ptr, end))
1794 /*NULL or empty string*/
1795 if (str_start == NULL || str_len == 0) {
1796 ADD_ERROR_NO_RETURN (ctx, g_strdup ("CustomAttribute: Null or empty enum name"));
1800 enum_name = (char *)g_memdup (str_start, str_len + 1);
1801 enum_name [str_len] = 0;
1802 type = mono_reflection_type_from_name (enum_name, ctx->image);
1804 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute: Invalid enum class %s", enum_name));
1810 klass = mono_class_from_mono_type (type);
1811 if (!klass || !klass->enumtype) {
1812 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute:Class %s::%s is not an enum", klass->name_space, klass->name));
1821 is_valid_fixed_param (VerifyContext *ctx, MonoType *mono_type, const char **_ptr, const char *end)
1824 const char *ptr = *_ptr;
1826 guint32 element_count, i;
1829 klass = mono_type->data.klass;
1830 type = mono_type->type;
1834 case MONO_TYPE_BOOLEAN:
1841 case MONO_TYPE_CHAR:
1855 case MONO_TYPE_STRING:
1857 return is_valid_ser_string (ctx, _ptr, end);
1859 case MONO_TYPE_OBJECT: {
1860 unsigned sub_type = 0;
1861 if (!safe_read8 (sub_type, ptr, end))
1862 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array type"));
1864 if (sub_type >= MONO_TYPE_BOOLEAN && sub_type <= MONO_TYPE_STRING) {
1868 if (sub_type == MONO_TYPE_ENUM) {
1869 klass = get_enum_by_encoded_name (ctx, &ptr, end);
1873 klass = klass->element_class;
1874 type = klass->byval_arg.type;
1877 if (sub_type == 0x50) { /*Type*/
1879 return is_valid_ser_string (ctx, _ptr, end);
1881 if (sub_type == MONO_TYPE_SZARRAY) {
1882 MonoType simple_type = {{0}};
1884 if (!safe_read8 (etype, ptr, end))
1885 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array element type"));
1887 if (etype == MONO_TYPE_ENUM) {
1888 klass = get_enum_by_encoded_name (ctx, &ptr, end);
1891 } else if (etype == 0x50 || etype == MONO_TYPE_CLASS) {
1892 klass = mono_defaults.systemtype_class;
1893 } else if ((etype >= MONO_TYPE_BOOLEAN && etype <= MONO_TYPE_STRING) || etype == 0x51) {
1894 simple_type.type = etype == 0x51 ? MONO_TYPE_OBJECT : (MonoTypeEnum)etype;
1895 klass = mono_class_from_mono_type (&simple_type);
1897 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype));
1899 type = MONO_TYPE_SZARRAY;
1902 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid boxed object type %x", sub_type));
1905 case MONO_TYPE_CLASS:
1906 if (klass && klass->enumtype) {
1907 klass = klass->element_class;
1908 type = klass->byval_arg.type;
1912 if (klass != mono_defaults.systemtype_class)
1913 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid class parameter type %s:%s ",klass->name_space, klass->name));
1915 return is_valid_ser_string (ctx, _ptr, end);
1917 case MONO_TYPE_VALUETYPE:
1918 if (!klass || !klass->enumtype)
1919 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid valuetype parameter expected enum %s:%s ",klass->name_space, klass->name));
1921 klass = klass->element_class;
1922 type = klass->byval_arg.type;
1925 case MONO_TYPE_SZARRAY:
1926 mono_type = &klass->byval_arg;
1927 if (!is_valid_cattr_type (mono_type))
1928 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %s:%s ",klass->name_space, klass->name));
1929 if (!safe_read32 (element_count, ptr, end))
1930 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid class parameter type %s:%s ",klass->name_space, klass->name));
1931 if (element_count == 0xFFFFFFFFu) {
1935 for (i = 0; i < element_count; ++i) {
1936 if (!is_valid_fixed_param (ctx, mono_type, &ptr, end))
1942 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid parameter type %x ", type));
1945 if (ADDP_IS_GREATER_OR_OVF (ptr, elem_size, end))
1946 FAIL (ctx, g_strdup ("CustomAttribute: Not enough space for element"));
1947 *_ptr = ptr + elem_size;
1952 is_valid_cattr_content (VerifyContext *ctx, MonoMethod *ctor, const char *ptr, guint32 size)
1955 unsigned prolog = 0;
1957 MonoMethodSignature *sig;
1962 FAIL (ctx, g_strdup ("CustomAttribute: Invalid constructor"));
1964 sig = mono_method_signature_checked (ctor, &error);
1965 if (!mono_error_ok (&error)) {
1966 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute: Invalid constructor signature %s", mono_error_get_message (&error)));
1967 mono_error_cleanup (&error);
1971 if (sig->sentinelpos != -1 || sig->call_convention == MONO_CALL_VARARG)
1972 FAIL (ctx, g_strdup ("CustomAttribute: Constructor cannot have VARAG signature"));
1976 if (!safe_read16 (prolog, ptr, end))
1977 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1980 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1982 args = sig->param_count;
1983 for (i = 0; i < args; ++i) {
1984 MonoType *arg_type = sig->params [i];
1985 if (!is_valid_fixed_param (ctx, arg_type, &ptr, end))
1989 if (!safe_read16 (num_named, ptr, end))
1990 FAIL (ctx, g_strdup ("CustomAttribute: Not enough space for num_named field"));
1992 for (i = 0; i < num_named; ++i) {
1993 MonoType *type, simple_type = {{0}};
1996 if (!safe_read8 (kind, ptr, end))
1997 FAIL (ctx, g_strdup_printf ("CustomAttribute: Not enough space for named parameter %d kind", i));
1998 if (kind != 0x53 && kind != 0x54)
1999 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid named parameter %d kind %x", i, kind));
2000 if (!safe_read8 (kind, ptr, end))
2001 FAIL (ctx, g_strdup_printf ("CustomAttribute: Not enough space for named parameter %d type", i));
2003 if (kind >= MONO_TYPE_BOOLEAN && kind <= MONO_TYPE_STRING) {
2004 simple_type.type = (MonoTypeEnum)kind;
2005 type = &simple_type;
2006 } else if (kind == MONO_TYPE_ENUM) {
2007 MonoClass *klass = get_enum_by_encoded_name (ctx, &ptr, end);
2010 type = &klass->byval_arg;
2011 } else if (kind == 0x50) {
2012 type = &mono_defaults.systemtype_class->byval_arg;
2013 } else if (kind == 0x51) {
2014 type = &mono_defaults.object_class->byval_arg;
2015 } else if (kind == MONO_TYPE_SZARRAY) {
2018 if (!safe_read8 (etype, ptr, end))
2019 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array element type"));
2021 if (etype == MONO_TYPE_ENUM) {
2022 klass = get_enum_by_encoded_name (ctx, &ptr, end);
2025 } else if (etype == 0x50 || etype == MONO_TYPE_CLASS) {
2026 klass = mono_defaults.systemtype_class;
2027 } else if ((etype >= MONO_TYPE_BOOLEAN && etype <= MONO_TYPE_STRING) || etype == 0x51) {
2028 simple_type.type = etype == 0x51 ? MONO_TYPE_OBJECT : (MonoTypeEnum)etype;
2029 klass = mono_class_from_mono_type (&simple_type);
2031 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype));
2033 type = &mono_array_class_get (klass, 1)->byval_arg;
2035 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid named parameter type %x", kind));
2038 if (!is_valid_ser_string (ctx, &ptr, end))
2041 if (!is_valid_fixed_param (ctx, type, &ptr, end))
2050 is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
2052 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2053 //TODO do proper verification
2054 return blob.size >= 1 && blob.size - 1 >= offset;
2058 is_valid_permission_set (VerifyContext *ctx, guint32 offset)
2060 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2061 //TODO do proper verification
2062 return blob.size >= 1 && blob.size - 1 >= offset;
2066 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
2069 unsigned signature = 0;
2070 const char *ptr = NULL, *end;
2072 if (!decode_signature_header (ctx, offset, &size, &ptr))
2073 FAIL (ctx, g_strdup ("StandAloneSig: Could not decode signature header"));
2076 if (!safe_read8 (signature, ptr, end))
2077 FAIL (ctx, g_strdup ("StandAloneSig: Not enough room for the call conv"));
2080 if (signature == 0x07)
2081 return parse_locals_signature (ctx, &ptr, end);
2083 /*F# and managed C++ produce standalonesig for fields even thou the spec doesn't mention it.*/
2084 if (signature == 0x06)
2085 return parse_field (ctx, &ptr, end);
2087 return parse_method_signature (ctx, &ptr, end, TRUE, TRUE);
2091 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
2094 const char *ptr = NULL, *end;
2096 if (!decode_signature_header (ctx, offset, &size, &ptr))
2097 FAIL (ctx, g_strdup ("PropertySig: Could not decode signature header"));
2100 return parse_property_signature (ctx, &ptr, end);
2104 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
2107 const char *ptr = NULL, *end;
2110 if (!decode_signature_header (ctx, offset, &size, &ptr))
2111 FAIL (ctx, g_strdup ("TypeSpec: Could not decode signature header"));
2114 if (!parse_custom_mods (ctx, &ptr, end))
2117 if (!safe_read8 (type, ptr, end))
2118 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for type"));
2120 if (type == MONO_TYPE_BYREF) {
2121 if (!safe_read8 (type, ptr, end))
2122 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for byref type"));
2123 if (type == MONO_TYPE_TYPEDBYREF)
2124 FAIL (ctx, g_strdup ("TypeSpec: Invalid type typedref&"));
2127 if (type == MONO_TYPE_TYPEDBYREF)
2131 return parse_type (ctx, &ptr, end);
2135 is_valid_methodspec_blob (VerifyContext *ctx, guint32 offset)
2138 const char *ptr = NULL, *end;
2140 unsigned count = 0, i;
2142 if (!decode_signature_header (ctx, offset, &size, &ptr))
2143 FAIL (ctx, g_strdup ("MethodSpec: Could not decode signature header"));
2146 if (!safe_read8 (type, ptr, end))
2147 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for call convention"));
2150 FAIL (ctx, g_strdup_printf ("MethodSpec: Invalid call convention 0x%x, expected 0x0A", type));
2152 if (!safe_read_cint (count, ptr, end))
2153 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for parameter count"));
2156 FAIL (ctx, g_strdup ("MethodSpec: Zero generic argument count"));
2158 for (i = 0; i < count; ++i) {
2159 if (!parse_custom_mods (ctx, &ptr, end))
2161 if (!parse_type (ctx, &ptr, end))
2162 FAIL (ctx, g_strdup_printf ("MethodSpec: Could not parse parameter %d", i + 1));
2168 is_valid_blob_object (VerifyContext *ctx, guint32 offset, guint32 minsize)
2170 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2171 guint32 entry_size, bytes;
2173 if (blob.size < offset)
2176 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
2179 if (entry_size < minsize)
2182 if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
2184 entry_size += bytes;
2186 return !ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size);
2190 is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
2192 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2193 guint32 size, entry_size, bytes;
2195 if (blob.size < offset)
2196 FAIL (ctx, g_strdup ("ContantValue: invalid offset"));
2198 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
2199 FAIL (ctx, g_strdup ("ContantValue: not enough space to decode size"));
2201 if (type == MONO_TYPE_STRING) {
2202 //String is encoded as: compressed_int:len len *bytes
2205 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size))
2206 FAIL (ctx, g_strdup_printf ("ContantValue: not enough space for string, required %d but got %d", entry_size * 2, blob.size - offset));
2212 case MONO_TYPE_BOOLEAN:
2217 case MONO_TYPE_CHAR:
2225 case MONO_TYPE_CLASS:
2235 g_assert_not_reached ();
2238 if (size != entry_size)
2239 FAIL (ctx, g_strdup_printf ("ContantValue: Expected size %d but got %d", size, entry_size));
2243 if (ADD_IS_GREATER_OR_OVF (offset, size, blob.size))
2244 FAIL (ctx, g_strdup_printf ("ContantValue: Not enough room for constant, required %d but have %d", size, blob.size - offset));
2246 if (type == MONO_TYPE_CLASS && read32 (ctx->data + blob.offset + offset))
2247 FAIL (ctx, g_strdup_printf ("ContantValue: Type is class but value is not null"));
2251 #define FAT_HEADER_INVALID_FLAGS ~(0x3 | 0x8 | 0x10 | 0xF000)
2252 //only 0x01, 0x40 and 0x80 are allowed
2253 #define SECTION_HEADER_INVALID_FLAGS 0x3E
2256 is_valid_method_header (VerifyContext *ctx, guint32 rva, guint32 *locals_token)
2258 unsigned local_vars_tok, code_size, offset = mono_cli_rva_image_map (ctx->image, rva);
2259 unsigned header = 0;
2260 unsigned fat_header = 0, size = 0, max_stack;
2261 const char *ptr = NULL, *end;
2265 if (offset == INVALID_ADDRESS)
2266 FAIL (ctx, g_strdup ("MethodHeader: Invalid RVA"));
2268 ptr = ctx->data + offset;
2269 end = ctx->data + ctx->size; /*no worries if it spawns multiple sections*/
2271 if (!safe_read8 (header, ptr, end))
2272 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for header"));
2274 switch (header & 0x3) {
2277 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid header type 0x%x", header & 0x3));
2280 if (ADDP_IS_GREATER_OR_OVF (ptr, header, end))
2281 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for method body. Required %d, but only %d is available", header, (int)(end - ptr)));
2286 if (!safe_read16 (fat_header, ptr, end))
2287 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for fat header"));
2289 size = (fat_header >> 12) & 0xF;
2291 FAIL (ctx, g_strdup ("MethodHeader: header size must be 3"));
2293 if (!safe_read16 (max_stack, ptr, end))
2294 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for max stack"));
2296 if (!safe_read32 (code_size, ptr, end))
2297 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for code size"));
2299 if (!safe_read32 (local_vars_tok, ptr, end))
2300 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for local vars tok"));
2302 if (local_vars_tok) {
2303 if (((local_vars_tok >> 24) & 0xFF) != 0x11)
2304 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature table 0x%x", ((local_vars_tok >> 24) & 0xFF)));
2305 if ((local_vars_tok & 0xFFFFFF) > ctx->image->tables [MONO_TABLE_STANDALONESIG].rows)
2306 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature points to invalid row 0x%x", local_vars_tok & 0xFFFFFF));
2307 if (!(local_vars_tok & 0xFFFFFF))
2308 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature with zero index"));
2309 *locals_token = local_vars_tok & 0xFFFFFF;
2312 if (fat_header & FAT_HEADER_INVALID_FLAGS)
2313 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid fat signature flags %x", fat_header & FAT_HEADER_INVALID_FLAGS));
2315 if (ADDP_IS_GREATER_OR_OVF (ptr, code_size, end))
2316 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for code %d", code_size));
2318 if (!(fat_header & 0x08))
2324 unsigned section_header = 0, section_size = 0;
2327 ptr = dword_align (ptr);
2328 if (!safe_read32 (section_header, ptr, end))
2329 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for data section header"));
2331 if (section_header & SECTION_HEADER_INVALID_FLAGS)
2332 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section header flags 0x%x", section_header & SECTION_HEADER_INVALID_FLAGS));
2334 is_fat = (section_header & METHOD_HEADER_SECTION_FAT_FORMAT) != 0;
2335 section_size = (section_header >> 8) & (is_fat ? 0xFFFFFF : 0xFF);
2337 if (section_size < 4)
2338 FAIL (ctx, g_strdup_printf ("MethodHeader: Section size too small"));
2340 if (ADDP_IS_GREATER_OR_OVF (ptr, section_size - 4, end)) /*must be section_size -4 as ptr was incremented by safe_read32*/
2341 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section content %d", section_size));
2343 if (section_header & METHOD_HEADER_SECTION_EHTABLE) {
2344 guint32 i, clauses = section_size / (is_fat ? 24 : 12);
2346 LAMEIMPL: MS emits section_size without accounting for header size.
2347 Mono does as the spec says. section_size is header + section
2348 MS's peverify happily accepts both.
2350 if ((clauses * (is_fat ? 24 : 12) != section_size) && (clauses * (is_fat ? 24 : 12) + 4 != section_size))
2351 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)));
2353 /* only verify the class token is verified as the rest is done by the IL verifier*/
2354 for (i = 0; i < clauses; ++i) {
2355 unsigned flags = *(unsigned char*)ptr;
2356 unsigned class_token = 0;
2357 ptr += (is_fat ? 20 : 8);
2358 if (!safe_read32 (class_token, ptr, end))
2359 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section %d", i));
2360 if (flags == MONO_EXCEPTION_CLAUSE_NONE && class_token) {
2361 guint table = mono_metadata_token_table (class_token);
2362 if (table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPESPEC)
2363 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token table %x", i, table));
2364 if (mono_metadata_token_index (class_token) > ctx->image->tables [table].rows)
2365 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token index %x", i, mono_metadata_token_index (class_token)));
2370 if (!(section_header & METHOD_HEADER_SECTION_MORE_SECTS))
2377 verify_module_table (VerifyContext *ctx)
2379 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
2380 guint32 data [MONO_MODULE_SIZE];
2382 if (table->rows != 1)
2383 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
2385 mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
2387 if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
2388 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
2390 if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
2391 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
2393 if (data [MONO_MODULE_ENC] != 0)
2394 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
2396 if (data [MONO_MODULE_ENCBASE] != 0)
2397 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
2401 verify_typeref_table (VerifyContext *ctx)
2403 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
2407 for (i = 0; i < table->rows; ++i) {
2408 mono_verifier_verify_typeref_row (ctx->image, i, &error);
2409 add_from_mono_error (ctx, &error);
2413 /*bits 9,11,14,15,19,21,24-31 */
2414 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
2416 verify_typedef_table (VerifyContext *ctx)
2418 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2419 guint32 data [MONO_TYPEDEF_SIZE];
2420 guint32 fieldlist = 1, methodlist = 1, visibility;
2423 if (table->rows == 0)
2424 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2426 for (i = 0; i < table->rows; ++i) {
2427 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2428 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
2429 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x rejected bits: 0x%08x", i, data [MONO_TYPEDEF_FLAGS], data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS));
2431 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
2432 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
2434 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
2435 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2437 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
2438 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2440 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) && (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
2441 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
2443 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
2444 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
2446 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
2447 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
2449 if (data [MONO_TYPEDEF_EXTENDS] && !is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
2450 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
2452 if (data [MONO_TYPEDEF_EXTENDS] && !get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
2453 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d zero coded extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
2455 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
2456 if ((visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) &&
2457 search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1) == -1)
2458 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d has nested visibility but no rows in the NestedClass table", i));
2460 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
2461 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
2463 if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2464 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
2466 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
2467 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));
2469 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
2470 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
2472 if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
2473 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
2475 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
2476 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));
2478 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
2479 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
2484 verify_typedef_table_full (VerifyContext *ctx)
2486 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2487 guint32 data [MONO_TYPEDEF_SIZE];
2490 if (table->rows == 0)
2491 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2493 for (i = 0; i < table->rows; ++i) {
2494 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2497 /*XXX it's ok if <module> extends object, or anything at all, actually. */
2498 /*if (data [MONO_TYPEDEF_EXTENDS] != 0)
2499 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
2504 if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
2505 if (data [MONO_TYPEDEF_EXTENDS])
2506 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
2508 gboolean is_sys_obj = typedef_is_system_object (ctx, data);
2509 gboolean has_parent = get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]) != 0;
2513 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
2516 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
2524 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
2526 verify_field_table (VerifyContext *ctx)
2528 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2529 guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
2532 module_field_list = (guint32)-1;
2533 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2534 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2535 module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
2538 for (i = 0; i < table->rows; ++i) {
2539 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2540 flags = data [MONO_FIELD_FLAGS];
2542 if (flags & INVALID_FIELD_FLAG_BITS)
2543 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
2545 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)
2546 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
2548 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
2549 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
2551 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
2552 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
2554 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
2555 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
2557 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
2558 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
2559 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
2561 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
2562 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2563 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2565 if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
2566 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2567 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
2569 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
2570 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
2571 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2573 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
2574 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
2576 if (data [MONO_FIELD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_FIELD_SIGNATURE], 1))
2577 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature blob token 0x%x", i, data [MONO_FIELD_SIGNATURE]));
2579 //TODO verify contant flag
2581 if (i + 1 < module_field_list) {
2582 guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
2583 if (!(flags & FIELD_ATTRIBUTE_STATIC))
2584 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
2585 if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
2586 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
2592 verify_field_table_full (VerifyContext *ctx)
2594 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2595 guint32 data [MONO_FIELD_SIZE];
2598 for (i = 0; i < table->rows; ++i) {
2599 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2601 if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
2602 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
2606 /*bits 8,9,10,11,13,14,15*/
2607 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
2609 verify_method_table (VerifyContext *ctx)
2611 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2612 guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
2613 guint32 paramlist = 1;
2614 gboolean is_ctor, is_cctor;
2618 module_method_list = (guint32)-1;
2619 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2620 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2621 module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
2624 for (i = 0; i < table->rows; ++i) {
2625 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2626 rva = data [MONO_METHOD_RVA];
2627 implflags = data [MONO_METHOD_IMPLFLAGS];
2628 flags = data [MONO_METHOD_FLAGS];
2629 access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
2630 code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
2633 if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
2634 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
2637 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
2639 if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
2640 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
2642 name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
2643 is_ctor = !strcmp (".ctor", name);
2644 is_cctor = !strcmp (".cctor", name);
2646 if ((is_ctor || is_cctor) &&
2647 search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
2648 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
2650 if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
2651 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
2653 if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
2654 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
2655 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
2656 if (flags & METHOD_ATTRIBUTE_FINAL)
2657 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and Final", i));
2658 if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
2659 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
2662 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
2663 ADD_WARNING (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
2665 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
2666 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
2668 //XXX no checks against cas stuff 10,11,12,13)
2670 //TODO check iface with .ctor (15,16)
2672 if (i + 1 < module_method_list) {
2673 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2674 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
2675 if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
2676 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
2677 if (access == METHOD_ATTRIBUTE_FAMILY || access == METHOD_ATTRIBUTE_FAM_AND_ASSEM || access == METHOD_ATTRIBUTE_FAM_OR_ASSEM)
2678 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public, Private or Assembly", i));
2681 //TODO check valuetype for synchronized
2683 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
2684 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
2686 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
2687 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
2688 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
2689 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2690 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but not Static", i));
2693 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
2694 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2695 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
2697 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
2698 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
2700 //TODO check signature contents
2703 if ((flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) || (implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
2704 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is either Abstract, InternalCall or PinvokeImpl", i));
2705 if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
2706 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
2708 if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2709 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
2712 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2714 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
2715 if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
2716 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
2718 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
2719 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
2721 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
2722 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
2724 if (data [MONO_METHOD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHOD_SIGNATURE], 1))
2725 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature blob token 0x%x", i, data [MONO_METHOD_SIGNATURE]));
2727 if (data [MONO_METHOD_PARAMLIST] == 0)
2728 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
2730 if (data [MONO_METHOD_PARAMLIST] < paramlist)
2731 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));
2733 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
2734 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
2736 paramlist = data [MONO_METHOD_PARAMLIST];
2742 verify_method_table_full (VerifyContext *ctx)
2744 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2745 guint32 data [MONO_METHOD_SIZE], rva, locals_token;
2748 for (i = 0; i < table->rows; ++i) {
2749 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2750 rva = data [MONO_METHOD_RVA];
2752 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
2753 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
2755 if (rva && !is_valid_method_header (ctx, rva, &locals_token))
2756 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
2761 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
2763 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2764 guint32 row = *current_method;
2765 guint32 paramlist, tmp;
2768 paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
2769 while (row < table->rows) {
2770 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
2771 if (tmp > paramlist) {
2772 *current_method = row;
2773 return tmp - paramlist;
2778 /*no more methods, all params apply to the last one*/
2779 *current_method = table->rows;
2784 #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))
2786 verify_param_table (VerifyContext *ctx)
2788 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
2789 guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
2790 gboolean first_param = TRUE;
2793 if (ctx->image->tables [MONO_TABLE_METHOD].rows == 0) {
2794 if (table->rows > 0)
2795 ADD_ERROR (ctx, g_strdup ("Param table has rows while the method table has zero"));
2799 remaining_params = get_next_param_count (ctx, ¤t_method);
2801 for (i = 0; i < table->rows; ++i) {
2802 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
2803 flags = data [MONO_PARAM_FLAGS];
2805 if (flags & INVALID_PARAM_FLAGS_BITS)
2806 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
2808 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
2809 if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
2810 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
2812 if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
2813 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
2816 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)
2817 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
2819 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
2820 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
2822 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
2823 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
2825 first_param = FALSE;
2826 sequence = data [MONO_PARAM_SEQUENCE];
2827 if (--remaining_params == 0) {
2828 remaining_params = get_next_param_count (ctx, ¤t_method);
2835 verify_interfaceimpl_table (VerifyContext *ctx)
2837 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
2838 guint32 data [MONO_INTERFACEIMPL_SIZE];
2841 for (i = 0; i < table->rows; ++i) {
2842 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
2843 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2844 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_INTERFACEIMPL_CLASS]));
2846 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2847 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
2849 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2850 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
2855 verify_memberref_table (VerifyContext *ctx)
2857 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2858 guint32 data [MONO_MEMBERREF_SIZE];
2861 for (i = 0; i < table->rows; ++i) {
2862 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2864 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2865 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
2867 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2868 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
2870 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
2871 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
2873 if (data [MONO_MEMBERREF_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_MEMBERREF_SIGNATURE], 1))
2874 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d invalid signature blob token 0x%x", i, data [MONO_MEMBERREF_SIGNATURE]));
2880 verify_memberref_table_full (VerifyContext *ctx)
2882 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2883 guint32 data [MONO_MEMBERREF_SIZE];
2886 for (i = 0; i < table->rows; ++i) {
2887 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2889 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
2890 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field 0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
2895 verify_constant_table (VerifyContext *ctx)
2897 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
2898 guint32 data [MONO_CONSTANT_SIZE], type;
2901 for (i = 0; i < table->rows; ++i) {
2902 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
2903 type = data [MONO_CONSTANT_TYPE];
2905 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
2906 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
2908 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2909 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
2911 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2912 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
2914 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
2915 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
2920 verify_cattr_table (VerifyContext *ctx)
2922 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2923 guint32 data [MONO_CUSTOM_ATTR_SIZE];
2926 for (i = 0; i < table->rows; ++i) {
2927 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2929 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
2930 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2932 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]))
2933 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Type field 0x%08x", i, data [MONO_CUSTOM_ATTR_TYPE]));
2935 if (data [MONO_CUSTOM_ATTR_VALUE] && !is_valid_blob_object (ctx, data [MONO_CUSTOM_ATTR_VALUE], 0))
2936 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d invalid value blob 0x%x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2941 verify_cattr_table_full (VerifyContext *ctx)
2944 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2947 guint32 data [MONO_CUSTOM_ATTR_SIZE], mtoken, size;
2950 for (i = 0; i < table->rows; ++i) {
2951 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2953 if (!is_valid_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
2954 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2956 mtoken = data [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
2957 switch (data [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
2958 case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
2959 mtoken |= MONO_TOKEN_METHOD_DEF;
2961 case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
2962 mtoken |= MONO_TOKEN_MEMBER_REF;
2965 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute constructor row %d Token 0x%08x", i, data [MONO_CUSTOM_ATTR_TYPE]));
2968 ctor = mono_get_method_checked (ctx->image, mtoken, NULL, NULL, &error);
2971 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute content row %d Could not load ctor due to %s", i, mono_error_get_message (&error)));
2972 mono_error_cleanup (&error);
2975 /*This can't fail since this is checked in is_valid_cattr_blob*/
2976 g_assert (decode_signature_header (ctx, data [MONO_CUSTOM_ATTR_VALUE], &size, &ptr));
2978 if (!is_valid_cattr_content (ctx, ctor, ptr, size)) {
2979 char *ctor_name = mono_method_full_name (ctor, TRUE);
2980 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute content row %d Value field 0x%08x ctor: %s", i, data [MONO_CUSTOM_ATTR_VALUE], ctor_name));
2987 verify_field_marshal_table (VerifyContext *ctx)
2989 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2990 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2993 for (i = 0; i < table->rows; ++i) {
2994 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2996 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2997 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
2999 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
3000 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
3002 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
3003 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
3005 if (!is_valid_blob_object (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE], 1))
3006 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d invalid NativeType blob 0x%x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
3011 verify_field_marshal_table_full (VerifyContext *ctx)
3013 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
3014 guint32 data [MONO_FIELD_MARSHAL_SIZE];
3017 for (i = 0; i < table->rows; ++i) {
3018 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
3020 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
3021 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
3026 verify_decl_security_table (VerifyContext *ctx)
3028 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
3029 guint32 data [MONO_DECL_SECURITY_SIZE];
3032 for (i = 0; i < table->rows; ++i) {
3033 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
3035 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
3036 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
3038 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
3039 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
3041 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
3042 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
3047 verify_decl_security_table_full (VerifyContext *ctx)
3049 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
3050 guint32 data [MONO_DECL_SECURITY_SIZE];
3053 for (i = 0; i < table->rows; ++i) {
3054 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
3056 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
3057 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
3062 verify_class_layout_table (VerifyContext *ctx)
3064 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
3065 guint32 data [MONO_CLASS_LAYOUT_SIZE];
3068 for (i = 0; i < table->rows; ++i) {
3069 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
3071 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3072 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
3074 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
3086 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
3092 verify_field_layout_table (VerifyContext *ctx)
3094 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
3095 guint32 data [MONO_FIELD_LAYOUT_SIZE];
3098 for (i = 0; i < table->rows; ++i) {
3099 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
3101 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
3102 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
3107 verify_standalonesig_table (VerifyContext *ctx)
3109 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
3110 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
3113 for (i = 0; i < table->rows; ++i) {
3114 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
3116 if (data [MONO_STAND_ALONE_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_STAND_ALONE_SIGNATURE], 1))
3117 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d invalid signature 0x%x", i, data [MONO_STAND_ALONE_SIGNATURE]));
3122 verify_standalonesig_table_full (VerifyContext *ctx)
3124 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
3125 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
3128 for (i = 0; i < table->rows; ++i) {
3129 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
3131 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
3132 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
3137 verify_eventmap_table (VerifyContext *ctx)
3139 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
3140 guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
3143 for (i = 0; i < table->rows; ++i) {
3144 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
3146 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3147 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
3149 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
3150 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
3152 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
3156 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
3158 verify_event_table (VerifyContext *ctx)
3160 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
3161 guint32 data [MONO_EVENT_SIZE];
3164 for (i = 0; i < table->rows; ++i) {
3165 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
3167 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
3168 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
3170 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
3171 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
3173 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
3174 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
3179 verify_event_table_full (VerifyContext *ctx)
3181 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
3182 MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
3183 guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
3184 gboolean found_add, found_remove;
3187 for (i = 0; i < table->rows; ++i) {
3188 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
3190 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
3191 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
3193 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
3195 //first we move to the first row for this event
3197 if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
3201 //now move forward looking for AddOn and RemoveOn rows
3202 found_add = found_remove = FALSE;
3203 while (idx < sema_table->rows) {
3204 mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
3205 if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
3207 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
3209 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
3210 found_remove = TRUE;
3211 if (found_add && found_remove)
3217 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
3219 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no RemoveOn associated method", i));
3224 verify_propertymap_table (VerifyContext *ctx)
3226 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
3227 guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
3230 for (i = 0; i < table->rows; ++i) {
3231 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
3233 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3234 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
3236 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
3237 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
3239 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
3243 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
3245 verify_property_table (VerifyContext *ctx)
3247 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
3248 guint32 data [MONO_PROPERTY_SIZE];
3251 for (i = 0; i < table->rows; ++i) {
3252 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
3254 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
3255 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
3257 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
3258 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
3260 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
3261 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
3263 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
3264 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
3265 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
3271 verify_methodimpl_table (VerifyContext *ctx)
3273 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
3274 guint32 data [MONO_METHODIMPL_SIZE];
3277 for (i = 0; i < table->rows; ++i) {
3278 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
3280 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3281 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
3283 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
3284 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
3286 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
3287 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
3289 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
3290 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
3292 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
3293 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
3298 verify_moduleref_table (VerifyContext *ctx)
3300 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
3301 guint32 data [MONO_MODULEREF_SIZE];
3304 for (i = 0; i < table->rows; ++i) {
3305 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
3307 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
3308 ADD_ERROR (ctx, g_strdup_printf ("Invalid ModuleRef row %d name field %08x", i, data [MONO_MODULEREF_NAME]));
3313 verify_typespec_table (VerifyContext *ctx)
3315 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
3316 guint32 data [MONO_TYPESPEC_SIZE];
3319 for (i = 0; i < table->rows; ++i) {
3320 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
3322 if (data [MONO_TYPESPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_TYPESPEC_SIGNATURE], 1))
3323 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
3328 verify_typespec_table_full (VerifyContext *ctx)
3330 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
3331 guint32 data [MONO_TYPESPEC_SIZE];
3334 for (i = 0; i < table->rows; ++i) {
3335 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
3336 ctx->token = (i + 1) | MONO_TOKEN_TYPE_SPEC;
3337 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
3338 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
3343 #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))
3345 verify_implmap_table (VerifyContext *ctx)
3347 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
3348 guint32 data [MONO_IMPLMAP_SIZE], cconv;
3351 for (i = 0; i < table->rows; ++i) {
3352 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
3354 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
3355 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
3357 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
3358 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
3359 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
3361 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
3362 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
3364 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
3365 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
3367 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
3368 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
3370 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
3371 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
3373 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULEREF].rows)
3374 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
3379 verify_fieldrva_table (VerifyContext *ctx)
3381 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
3382 guint32 data [MONO_FIELD_RVA_SIZE];
3385 for (i = 0; i < table->rows; ++i) {
3386 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
3388 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
3389 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
3391 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
3392 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
3396 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 14) | (1 << 15))
3398 verify_assembly_table (VerifyContext *ctx)
3400 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
3401 guint32 data [MONO_ASSEMBLY_SIZE], hash;
3404 if (table->rows > 1)
3405 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
3407 for (i = 0; i < table->rows; ++i) {
3408 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
3410 hash = data [MONO_ASSEMBLY_HASH_ALG];
3411 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
3412 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
3414 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
3415 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
3417 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY], 1))
3418 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
3420 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
3421 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
3423 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
3424 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
3428 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~((1 << 0) | (1 << 8) | (1 << 14) | (1 << 15))
3430 verify_assemblyref_table (VerifyContext *ctx)
3432 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
3433 guint32 data [MONO_ASSEMBLYREF_SIZE];
3436 for (i = 0; i < table->rows; ++i) {
3437 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
3439 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
3440 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
3442 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY], 1))
3443 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
3445 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
3446 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
3448 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
3449 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
3451 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE], 1))
3452 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
3456 #define INVALID_FILE_FLAGS_BITS ~(1)
3458 verify_file_table (VerifyContext *ctx)
3460 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
3461 guint32 data [MONO_FILE_SIZE];
3464 for (i = 0; i < table->rows; ++i) {
3465 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
3467 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
3468 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
3470 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
3471 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
3473 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE], 1))
3474 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
3478 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
3480 verify_exportedtype_table (VerifyContext *ctx)
3482 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
3483 guint32 data [MONO_EXP_TYPE_SIZE];
3486 for (i = 0; i < table->rows; ++i) {
3487 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
3489 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
3490 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
3492 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
3493 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
3495 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
3496 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
3498 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3499 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
3501 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3502 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
3504 /*nested type can't have a namespace*/
3505 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
3506 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
3510 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
3512 verify_manifest_resource_table (VerifyContext *ctx)
3514 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)ctx->image->image_info;
3515 MonoCLIHeader *ch = &iinfo->cli_cli_header;
3516 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
3517 guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
3520 resources_size = ch->ch_resources.size;
3522 for (i = 0; i < table->rows; ++i) {
3523 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
3525 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
3526 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
3528 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
3529 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
3531 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
3532 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
3534 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
3535 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
3537 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3538 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3540 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
3541 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])));
3543 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
3544 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
3546 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
3547 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
3552 verify_nested_class_table (VerifyContext *ctx)
3554 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3555 guint32 data [MONO_NESTED_CLASS_SIZE];
3558 for (i = 0; i < table->rows; ++i) {
3559 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
3561 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3562 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
3563 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3564 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3565 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
3566 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3570 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
3572 verify_generic_param_table (VerifyContext *ctx)
3574 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
3575 guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
3576 int i, param_number = 0;
3578 for (i = 0; i < table->rows; ++i) {
3579 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
3581 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
3582 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
3584 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
3585 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
3587 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
3588 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
3590 token = data [MONO_GENERICPARAM_OWNER];
3592 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
3593 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
3595 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
3596 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
3598 if (token != last_token) {
3603 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
3604 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));
3611 verify_method_spec_table (VerifyContext *ctx)
3613 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3614 guint32 data [MONO_METHODSPEC_SIZE];
3617 for (i = 0; i < table->rows; ++i) {
3618 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3620 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3621 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
3623 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3624 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
3626 if (data [MONO_METHODSPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHODSPEC_SIGNATURE], 1))
3627 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid signature token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3632 verify_method_spec_table_full (VerifyContext *ctx)
3634 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3635 guint32 data [MONO_METHODSPEC_SIZE];
3638 for (i = 0; i < table->rows; ++i) {
3639 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3641 if (!is_valid_methodspec_blob (ctx, data [MONO_METHODSPEC_SIGNATURE]))
3642 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3647 verify_generic_param_constraint_table (VerifyContext *ctx)
3649 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
3650 guint32 data [MONO_GENPARCONSTRAINT_SIZE];
3652 guint32 last_owner = 0, last_constraint = 0;
3654 for (i = 0; i < table->rows; ++i) {
3655 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
3657 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
3658 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_GENPARCONSTRAINT_GENERICPAR]));
3660 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3661 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
3663 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3664 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
3666 if (last_owner > data [MONO_GENPARCONSTRAINT_GENERICPAR])
3667 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]));
3669 if (last_owner == data [MONO_GENPARCONSTRAINT_GENERICPAR]) {
3670 if (last_constraint == data [MONO_GENPARCONSTRAINT_CONSTRAINT])
3671 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has duplicate constraint 0x%08x", i, last_constraint));
3673 last_owner = data [MONO_GENPARCONSTRAINT_GENERICPAR];
3675 last_constraint = data [MONO_GENPARCONSTRAINT_CONSTRAINT];
3682 const char *name_space;
3683 guint32 resolution_scope;
3687 typedef_hash (gconstpointer _key)
3689 const TypeDefUniqueId *key = (const TypeDefUniqueId *)_key;
3690 return g_str_hash (key->name) ^ g_str_hash (key->name_space) ^ key->resolution_scope; /*XXX better salt the int key*/
3694 typedef_equals (gconstpointer _a, gconstpointer _b)
3696 const TypeDefUniqueId *a = (const TypeDefUniqueId *)_a;
3697 const TypeDefUniqueId *b = (const TypeDefUniqueId *)_b;
3698 return !strcmp (a->name, b->name) && !strcmp (a->name_space, b->name_space) && a->resolution_scope == b->resolution_scope;
3702 verify_typedef_table_global_constraints (VerifyContext *ctx)
3705 guint32 data [MONO_TYPEDEF_SIZE];
3706 guint32 nested_data [MONO_NESTED_CLASS_SIZE];
3707 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
3708 MonoTableInfo *nested_table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3709 GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3711 for (i = 0; i < table->rows; ++i) {
3713 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3714 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
3716 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAME]);
3717 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAMESPACE]);
3718 type->resolution_scope = 0;
3720 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
3721 if (visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) {
3722 int res = search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1);
3723 g_assert (res >= 0);
3725 mono_metadata_decode_row (nested_table, res, nested_data, MONO_NESTED_CLASS_SIZE);
3726 type->resolution_scope = nested_data [MONO_NESTED_CLASS_ENCLOSING];
3729 if (g_hash_table_lookup (unique_types, type)) {
3730 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));
3731 g_hash_table_destroy (unique_types);
3735 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3738 g_hash_table_destroy (unique_types);
3742 verify_typeref_table_global_constraints (VerifyContext *ctx)
3745 guint32 data [MONO_TYPEREF_SIZE];
3746 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
3747 GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3749 for (i = 0; i < table->rows; ++i) {
3750 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3751 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
3753 type->resolution_scope = data [MONO_TYPEREF_SCOPE];
3754 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAME]);
3755 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAMESPACE]);
3757 if (g_hash_table_lookup (unique_types, type)) {
3758 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));
3759 g_hash_table_destroy (unique_types);
3763 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3766 g_hash_table_destroy (unique_types);
3771 guint32 method_declaration;
3772 } MethodImplUniqueId;
3775 methodimpl_hash (gconstpointer _key)
3777 const MethodImplUniqueId *key = (const MethodImplUniqueId *)_key;
3778 return key->klass ^ key->method_declaration;
3782 methodimpl_equals (gconstpointer _a, gconstpointer _b)
3784 const MethodImplUniqueId *a = (const MethodImplUniqueId *)_a;
3785 const MethodImplUniqueId *b = (const MethodImplUniqueId *)_b;
3786 return a->klass == b->klass && a->method_declaration == b->method_declaration;
3790 verify_methodimpl_table_global_constraints (VerifyContext *ctx)
3793 guint32 data [MONO_METHODIMPL_SIZE];
3794 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
3795 GHashTable *unique_impls = g_hash_table_new_full (&methodimpl_hash, &methodimpl_equals, g_free, NULL);
3797 for (i = 0; i < table->rows; ++i) {
3798 MethodImplUniqueId *impl = g_new (MethodImplUniqueId, 1);
3799 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
3801 impl->klass = data [MONO_METHODIMPL_CLASS];
3802 impl->method_declaration = data [MONO_METHODIMPL_DECLARATION];
3804 if (g_hash_table_lookup (unique_impls, impl)) {
3805 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("MethodImpl table row %d has duplicate for tuple (0x%x, 0x%x)", impl->klass, impl->method_declaration));
3806 g_hash_table_destroy (unique_impls);
3810 g_hash_table_insert (unique_impls, impl, GUINT_TO_POINTER (1));
3813 g_hash_table_destroy (unique_impls);
3818 verify_tables_data_global_constraints (VerifyContext *ctx)
3820 verify_typedef_table_global_constraints (ctx);
3824 verify_tables_data_global_constraints_full (VerifyContext *ctx)
3826 verify_typeref_table (ctx);
3827 verify_typeref_table_global_constraints (ctx);
3828 verify_methodimpl_table_global_constraints (ctx);
3832 verify_tables_data (VerifyContext *ctx)
3834 OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
3835 guint32 size = 0, tables_offset;
3838 for (i = 0; i < 0x2D; ++i) {
3839 MonoTableInfo *table = &ctx->image->tables [i];
3841 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
3842 if (tmp_size < size) {
3850 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
3852 tables_offset = ctx->image->tables_base - ctx->data;
3853 if (!bounds_check_offset (&tables_area, tables_offset, size))
3854 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)));
3856 verify_module_table (ctx);
3858 /*Obfuscators love to place broken stuff in the typeref table
3859 verify_typeref_table (ctx);
3861 verify_typedef_table (ctx);
3863 verify_field_table (ctx);
3865 verify_method_table (ctx);
3867 verify_param_table (ctx);
3869 verify_interfaceimpl_table (ctx);
3871 verify_memberref_table (ctx);
3873 verify_constant_table (ctx);
3875 verify_cattr_table (ctx);
3877 verify_field_marshal_table (ctx);
3879 verify_decl_security_table (ctx);
3881 verify_class_layout_table (ctx);
3883 verify_field_layout_table (ctx);
3885 verify_standalonesig_table (ctx);
3887 verify_eventmap_table (ctx);
3889 verify_event_table (ctx);
3891 verify_propertymap_table (ctx);
3893 verify_property_table (ctx);
3895 verify_methodimpl_table (ctx);
3897 verify_moduleref_table (ctx);
3899 verify_typespec_table (ctx);
3901 verify_implmap_table (ctx);
3903 verify_fieldrva_table (ctx);
3905 verify_assembly_table (ctx);
3907 verify_assemblyref_table (ctx);
3909 verify_file_table (ctx);
3911 verify_exportedtype_table (ctx);
3913 verify_manifest_resource_table (ctx);
3915 verify_nested_class_table (ctx);
3917 verify_generic_param_table (ctx);
3919 verify_method_spec_table (ctx);
3921 verify_generic_param_constraint_table (ctx);
3923 verify_tables_data_global_constraints (ctx);
3927 init_verify_context (VerifyContext *ctx, MonoImage *image, gboolean report_error)
3929 memset (ctx, 0, sizeof (VerifyContext));
3931 ctx->report_error = report_error;
3932 ctx->report_warning = FALSE; //export this setting in the API
3934 ctx->size = image->raw_data_len;
3935 ctx->data = image->raw_data;
3939 cleanup_context (VerifyContext *ctx, GSList **error_list)
3941 g_free (ctx->sections);
3943 *error_list = ctx->errors;
3945 mono_free_verify_list (ctx->errors);
3950 cleanup_context_checked (VerifyContext *ctx, MonoError *error)
3952 g_free (ctx->sections);
3954 MonoVerifyInfo *info = (MonoVerifyInfo *)ctx->errors->data;
3955 mono_error_set_bad_image (error, ctx->image, "%s", info->message);
3956 mono_free_verify_list (ctx->errors);
3962 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3966 if (!mono_verifier_is_enabled_for_image (image))
3969 init_verify_context (&ctx, image, error_list != NULL);
3970 ctx.stage = STAGE_PE;
3972 verify_msdos_header (&ctx);
3974 verify_pe_header (&ctx);
3976 verify_pe_optional_header (&ctx);
3978 load_section_table (&ctx);
3980 load_data_directories (&ctx);
3982 verify_import_table (&ctx);
3984 /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
3985 verify_resources_table (&ctx);
3988 return cleanup_context (&ctx, error_list);
3992 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3996 if (!mono_verifier_is_enabled_for_image (image))
3999 init_verify_context (&ctx, image, error_list != NULL);
4000 ctx.stage = STAGE_CLI;
4002 verify_cli_header (&ctx);
4004 verify_metadata_header (&ctx);
4006 verify_tables_schema (&ctx);
4009 return cleanup_context (&ctx, error_list);
4014 * Verifies basic table constraints such as global table invariants (sorting, field monotonicity, etc).
4015 * Other verification checks are meant to be done lazily by the runtime. Those include:
4016 * blob items (signatures, method headers, custom attributes, etc)
4017 * type semantics related
4019 * stuff that should not block other pieces from running such as bad types/methods/fields/etc.
4021 * The whole idea is that if this succeed the runtime is free to play around safely but any complex
4022 * operation still need more checking.
4025 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
4029 if (!mono_verifier_is_enabled_for_image (image))
4032 init_verify_context (&ctx, image, error_list != NULL);
4033 ctx.stage = STAGE_TABLES;
4035 verify_tables_data (&ctx);
4037 return cleanup_context (&ctx, error_list);
4042 * Verifies all other constraints.
4045 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
4049 if (!mono_verifier_is_enabled_for_image (image))
4052 init_verify_context (&ctx, image, error_list != NULL);
4053 ctx.stage = STAGE_TABLES;
4055 verify_typedef_table_full (&ctx);
4057 verify_field_table_full (&ctx);
4059 verify_method_table_full (&ctx);
4061 verify_memberref_table_full (&ctx);
4063 verify_cattr_table_full (&ctx);
4065 verify_field_marshal_table_full (&ctx);
4067 verify_decl_security_table_full (&ctx);
4069 verify_standalonesig_table_full (&ctx);
4071 verify_event_table_full (&ctx);
4073 verify_typespec_table_full (&ctx);
4075 verify_method_spec_table_full (&ctx);
4077 verify_tables_data_global_constraints_full (&ctx);
4080 return cleanup_context (&ctx, error_list);
4084 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4088 if (!mono_verifier_is_enabled_for_image (image))
4091 init_verify_context (&ctx, image, error_list != NULL);
4092 ctx.stage = STAGE_TABLES;
4094 is_valid_field_signature (&ctx, offset);
4095 return cleanup_context (&ctx, error_list);
4099 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
4102 guint32 locals_token;
4104 if (!mono_verifier_is_enabled_for_image (image))
4107 init_verify_context (&ctx, image, error_list != NULL);
4108 ctx.stage = STAGE_TABLES;
4110 is_valid_method_header (&ctx, offset, &locals_token);
4112 guint32 sig_offset = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_STANDALONESIG], locals_token - 1, MONO_STAND_ALONE_SIGNATURE);
4113 is_valid_standalonesig_blob (&ctx, sig_offset);
4116 return cleanup_context (&ctx, error_list);
4120 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, MonoError *error)
4126 if (!mono_verifier_is_enabled_for_image (image))
4129 init_verify_context (&ctx, image, TRUE);
4130 ctx.stage = STAGE_TABLES;
4132 is_valid_method_signature (&ctx, offset);
4133 /*XXX This returns a bad image exception, it might be the case that the right exception is method load.*/
4134 return cleanup_context_checked (&ctx, error);
4138 mono_verifier_verify_memberref_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
4142 if (!mono_verifier_is_enabled_for_image (image))
4145 init_verify_context (&ctx, image, error_list != NULL);
4146 ctx.stage = STAGE_TABLES;
4148 is_valid_memberref_method_signature (&ctx, offset);
4149 return cleanup_context (&ctx, error_list);
4153 mono_verifier_verify_memberref_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4157 if (!mono_verifier_is_enabled_for_image (image))
4160 init_verify_context (&ctx, image, error_list != NULL);
4161 ctx.stage = STAGE_TABLES;
4163 is_valid_field_signature (&ctx, offset);
4164 return cleanup_context (&ctx, error_list);
4168 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
4172 if (!mono_verifier_is_enabled_for_image (image))
4175 init_verify_context (&ctx, image, error_list != NULL);
4176 ctx.stage = STAGE_TABLES;
4178 is_valid_standalonesig_blob (&ctx, offset);
4179 return cleanup_context (&ctx, error_list);
4183 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
4187 if (!mono_verifier_is_enabled_for_image (image))
4190 init_verify_context (&ctx, image, error_list != NULL);
4191 ctx.stage = STAGE_TABLES;
4194 is_valid_typespec_blob (&ctx, offset);
4195 return cleanup_context (&ctx, error_list);
4199 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
4203 if (!mono_verifier_is_enabled_for_image (image))
4206 init_verify_context (&ctx, image, error_list != NULL);
4207 ctx.stage = STAGE_TABLES;
4209 is_valid_methodspec_blob (&ctx, offset);
4210 return cleanup_context (&ctx, error_list);
4214 verify_user_string (VerifyContext *ctx, guint32 offset)
4216 OffsetAndSize heap_us = get_metadata_stream (ctx, &ctx->image->heap_us);
4217 guint32 entry_size, bytes;
4219 if (heap_us.size < offset)
4220 ADD_ERROR (ctx, g_strdup ("User string offset beyond heap_us size"));
4222 if (!decode_value (ctx->data + offset + heap_us.offset, heap_us.size - heap_us.offset, &entry_size, &bytes))
4223 ADD_ERROR (ctx, g_strdup ("Could not decode user string blob size"));
4225 if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
4226 ADD_ERROR (ctx, g_strdup ("User string size overflow"));
4228 entry_size += bytes;
4230 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, heap_us.size))
4231 ADD_ERROR (ctx, g_strdup ("User string oveflow heap_us"));
4235 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
4239 if (!mono_verifier_is_enabled_for_image (image))
4242 init_verify_context (&ctx, image, error_list != NULL);
4243 ctx.stage = STAGE_TABLES;
4245 verify_user_string (&ctx, offset);
4247 return cleanup_context (&ctx, error_list);
4251 mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, GSList **error_list)
4255 if (!mono_verifier_is_enabled_for_image (image))
4258 init_verify_context (&ctx, image, error_list != NULL);
4259 ctx.stage = STAGE_TABLES;
4261 is_valid_cattr_blob (&ctx, offset);
4263 return cleanup_context (&ctx, error_list);
4267 mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, GSList **error_list)
4271 if (!mono_verifier_is_enabled_for_image (image))
4274 init_verify_context (&ctx, image, error_list != NULL);
4275 ctx.stage = STAGE_TABLES;
4277 is_valid_cattr_content (&ctx, ctor, (const char*)data, size);
4279 return cleanup_context (&ctx, error_list);
4283 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
4285 MonoMethodSignature *original_sig;
4286 if (!mono_verifier_is_enabled_for_image (image))
4289 original_sig = mono_method_signature (method);
4290 if (original_sig->call_convention == MONO_CALL_VARARG) {
4291 if (original_sig->hasthis != signature->hasthis)
4293 if (original_sig->call_convention != signature->call_convention)
4295 if (original_sig->explicit_this != signature->explicit_this)
4297 if (original_sig->pinvoke != signature->pinvoke)
4299 if (original_sig->sentinelpos != signature->sentinelpos)
4301 } else if (!mono_metadata_signature_equal (signature, original_sig)) {
4309 mono_verifier_verify_typeref_row (MonoImage *image, guint32 row, MonoError *error)
4311 MonoTableInfo *table = &image->tables [MONO_TABLE_TYPEREF];
4312 guint32 data [MONO_TYPEREF_SIZE];
4316 if (!mono_verifier_is_enabled_for_image (image))
4319 if (row >= table->rows) {
4320 mono_error_set_bad_image (error, image, "Invalid typeref row %d - table has %d rows", row, table->rows);
4324 mono_metadata_decode_row (table, row, data, MONO_TYPEREF_SIZE);
4325 if (!is_valid_coded_index_with_image (image, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE])) {
4326 mono_error_set_bad_image (error, image, "Invalid typeref row %d coded index 0x%08x", row, data [MONO_TYPEREF_SCOPE]);
4330 if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE])) {
4331 mono_error_set_bad_image (error, image, "The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", row);
4335 if (!data [MONO_TYPEREF_NAME] || !is_valid_string_full_with_image (image, data [MONO_TYPEREF_NAME], FALSE)) {
4336 mono_error_set_bad_image (error, image, "Invalid typeref row %d name token 0x%08x", row, data [MONO_TYPEREF_NAME]);
4340 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_string_full_with_image (image, data [MONO_TYPEREF_NAMESPACE], FALSE)) {
4341 mono_error_set_bad_image (error, image, "Invalid typeref row %d namespace token 0x%08x", row, data [MONO_TYPEREF_NAMESPACE]);
4348 /*Perform additional verification including metadata ones*/
4350 mono_verifier_verify_methodimpl_row (MonoImage *image, guint32 row, MonoError *error)
4352 MonoMethod *declaration, *body;
4353 MonoMethodSignature *body_sig, *decl_sig;
4354 MonoTableInfo *table = &image->tables [MONO_TABLE_METHODIMPL];
4355 guint32 data [MONO_METHODIMPL_SIZE];
4359 if (!mono_verifier_is_enabled_for_image (image))
4362 if (row >= table->rows) {
4363 mono_error_set_bad_image (error, image, "Invalid methodimpl row %d - table has %d rows", row, table->rows);
4367 mono_metadata_decode_row (table, row, data, MONO_METHODIMPL_SIZE);
4369 body = method_from_method_def_or_ref (image, data [MONO_METHODIMPL_BODY], NULL, error);
4373 declaration = method_from_method_def_or_ref (image, data [MONO_METHODIMPL_DECLARATION], NULL, error);
4378 mono_class_setup_supertypes (class);
4379 if (!mono_class_has_parent (class, body->klass)) {
4380 mono_error_set_bad_image (error, image, "Invalid methodimpl body doesn't belong to parent for row %x", row);
4384 if (!(body_sig = mono_method_signature_checked (body, error))) {
4388 if (!(decl_sig = mono_method_signature_checked (declaration, error))) {
4392 if (!mono_verifier_is_signature_compatible (decl_sig, body_sig)) {
4393 mono_error_set_bad_image (error, image, "Invalid methodimpl body signature not compatible with declaration row %x", row);
4402 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
4408 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
4414 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
4420 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
4426 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4432 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
4438 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, MonoError *error)
4445 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
4451 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
4457 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
4463 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
4469 mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, GSList **error_list)
4475 mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, GSList **error_list)
4481 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
4488 mono_verifier_verify_typeref_row (MonoImage *image, guint32 row, MonoError *error)
4495 mono_verifier_verify_methodimpl_row (MonoImage *image, guint32 row, MonoError *error)
4502 mono_verifier_verify_memberref_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
4508 mono_verifier_verify_memberref_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4513 #endif /* DISABLE_VERIFIER */