2 * metadata-verify.c: Metadata verfication support
5 * Mono Project (http://www.mono-project.com)
7 * Copyright (C) 2005-2008 Novell, Inc. (http://www.novell.com)
9 #include <mono/metadata/object-internals.h>
10 #include <mono/metadata/verify.h>
11 #include <mono/metadata/verify-internals.h>
12 #include <mono/metadata/opcodes.h>
13 #include <mono/metadata/tabledefs.h>
14 #include <mono/metadata/reflection.h>
15 #include <mono/metadata/debug-helpers.h>
16 #include <mono/metadata/mono-endian.h>
17 #include <mono/metadata/metadata.h>
18 #include <mono/metadata/metadata-internals.h>
19 #include <mono/metadata/class-internals.h>
20 #include <mono/metadata/tokentype.h>
21 #include <mono/metadata/security-manager.h>
22 #include <mono/metadata/security-core-clr.h>
23 #include <mono/metadata/cil-coff.h>
24 #include <mono/metadata/attrdefs.h>
25 #include <mono/utils/strenc.h>
26 #include <mono/utils/mono-error-internals.h>
31 #ifndef DISABLE_VERIFIER
33 TODO add fail fast mode
34 TODO add PE32+ support
35 TODO verify the entry point RVA and content.
36 TODO load_section_table and load_data_directories must take PE32+ into account
37 TODO add section relocation support
38 TODO verify the relocation table, since we really don't use, no need so far.
39 TODO do full PECOFF resources verification
40 TODO verify in the CLI header entry point and resources
41 TODO implement null token typeref validation
42 TODO verify table wide invariants for typedef (sorting and uniqueness)
43 TODO implement proper authenticode data directory validation
44 TODO verify properties that require multiple tables to be valid
45 FIXME use subtraction based bounds checking to avoid overflows
46 FIXME get rid of metadata_streams and other fields from VerifyContext
49 #ifdef MONO_VERIFIER_DEBUG
50 #define VERIFIER_DEBUG(code) do { code; } while (0)
52 #define VERIFIER_DEBUG(code)
55 #define INVALID_OFFSET ((guint32)-1)
56 #define INVALID_ADDRESS 0xffffffff
66 RESOURCE_TABLE_IDX = 2,
67 CERTIFICATE_TABLE_IDX = 4,
68 RELOCATION_TABLE_IDX = 5,
82 #define INVALID_TABLE (0xFF)
83 /*format: number of bits, number of tables, tables{n. tables} */
84 const static unsigned char coded_index_desc[] = {
85 #define TYPEDEF_OR_REF_DESC (0)
92 #define HAS_CONSTANT_DESC (TYPEDEF_OR_REF_DESC + 5)
99 #define HAS_CATTR_DESC (HAS_CONSTANT_DESC + 5)
107 MONO_TABLE_INTERFACEIMPL,
108 MONO_TABLE_MEMBERREF,
110 MONO_TABLE_DECLSECURITY,
113 MONO_TABLE_STANDALONESIG,
114 MONO_TABLE_MODULEREF,
117 MONO_TABLE_ASSEMBLYREF,
119 MONO_TABLE_EXPORTEDTYPE,
120 MONO_TABLE_MANIFESTRESOURCE,
121 MONO_TABLE_GENERICPARAM,
123 #define HAS_FIELD_MARSHAL_DESC (HAS_CATTR_DESC + 22)
129 #define HAS_DECL_SECURITY_DESC (HAS_FIELD_MARSHAL_DESC + 4)
136 #define MEMBERREF_PARENT_DESC (HAS_DECL_SECURITY_DESC + 5)
145 #define HAS_SEMANTICS_DESC (MEMBERREF_PARENT_DESC + 7)
151 #define METHODDEF_OR_REF_DESC (HAS_SEMANTICS_DESC + 4)
155 MONO_TABLE_MEMBERREF,
157 #define MEMBER_FORWARDED_DESC (METHODDEF_OR_REF_DESC + 4)
163 #define IMPLEMENTATION_DESC (MEMBER_FORWARDED_DESC + 4)
167 MONO_TABLE_ASSEMBLYREF,
168 MONO_TABLE_EXPORTEDTYPE,
170 #define CATTR_TYPE_DESC (IMPLEMENTATION_DESC + 5)
176 MONO_TABLE_MEMBERREF,
179 #define RES_SCOPE_DESC (CATTR_TYPE_DESC + 7)
183 MONO_TABLE_MODULEREF,
184 MONO_TABLE_ASSEMBLYREF,
187 #define TYPE_OR_METHODDEF_DESC (RES_SCOPE_DESC + 6)
197 guint32 translated_offset;
209 guint32 rellocationsRVA;
210 guint16 numberOfRelocations;
225 gboolean report_error;
226 gboolean report_warning;
229 DataDirectory data_directories [16];
230 guint32 section_count;
231 SectionHeader *sections;
233 OffsetAndSize metadata_streams [5]; //offset from begin of the image
236 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception) \
238 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
239 vinfo->info.status = __status; \
240 vinfo->info.message = ( __msg); \
241 vinfo->exception_type = (__exception); \
242 (__ctx)->errors = g_slist_prepend ((__ctx)->errors, vinfo); \
245 #define ADD_WARNING(__ctx, __msg) \
247 if ((__ctx)->report_warning) { \
248 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_WARNING, MONO_EXCEPTION_INVALID_PROGRAM); \
249 (__ctx)->valid = 0; \
254 #define ADD_ERROR_NO_RETURN(__ctx, __msg) \
256 if ((__ctx)->report_error) \
257 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
258 (__ctx)->valid = 0; \
261 #define ADD_ERROR(__ctx, __msg) \
263 if ((__ctx)->report_error) \
264 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
265 (__ctx)->valid = 0; \
269 #define FAIL(__ctx, __msg) \
271 if ((__ctx)->report_error) \
272 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
273 (__ctx)->valid = 0; \
277 #define CHECK_STATE() do { if (!ctx.valid) goto cleanup; } while (0)
279 #define CHECK_ERROR() do { if (!ctx->valid) return; } while (0)
281 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
282 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
284 #if SIZEOF_VOID_P == 4
285 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
287 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
290 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
291 #define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
294 dword_align (const char *ptr)
296 #if SIZEOF_VOID_P == 8
297 return (const char *) (((guint64) (ptr + 3)) & ~3);
299 return (const char *) (((guint32) (ptr + 3)) & ~3);
304 add_from_mono_error (VerifyContext *ctx, MonoError *error)
306 if (mono_error_ok (error))
309 ADD_ERROR (ctx, g_strdup (mono_error_get_message (error)));
310 mono_error_cleanup (error);
314 pe_signature_offset (VerifyContext *ctx)
316 return read32 (ctx->data + 0x3c);
320 pe_header_offset (VerifyContext *ctx)
322 return read32 (ctx->data + 0x3c) + 4;
326 bounds_check_virtual_address (VerifyContext *ctx, guint32 rva, guint32 size)
330 if (rva + size < rva) //overflow
333 if (ctx->stage > STAGE_PE) {
334 MonoCLIImageInfo *iinfo = ctx->image->image_info;
335 const int top = iinfo->cli_section_count;
336 MonoSectionTable *tables = iinfo->cli_section_tables;
339 for (i = 0; i < top; i++) {
340 guint32 base = tables->st_virtual_address;
341 guint32 end = base + tables->st_raw_data_size;
343 if (rva >= base && rva + size <= end)
346 /*if ((addr >= tables->st_virtual_address) &&
347 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
349 return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
359 for (i = 0; i < ctx->section_count; ++i) {
360 guint32 base = ctx->sections [i].baseRVA;
361 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
362 if (rva >= base && rva + size <= end)
369 bounds_check_datadir (DataDirectory *dir, guint32 offset, guint32 size)
371 if (dir->translated_offset > offset)
373 if (dir->size < size)
375 return offset + size <= dir->translated_offset + dir->size;
379 bounds_check_offset (OffsetAndSize *off, guint32 offset, guint32 size)
381 if (off->offset > offset)
384 if (off->size < size)
387 return offset + size <= off->offset + off->size;
391 translate_rva (VerifyContext *ctx, guint32 rva)
395 if (ctx->stage > STAGE_PE)
396 return mono_cli_rva_image_map (ctx->image, rva);
401 for (i = 0; i < ctx->section_count; ++i) {
402 guint32 base = ctx->sections [i].baseRVA;
403 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
404 if (rva >= base && rva <= end) {
405 guint32 res = (rva - base) + ctx->sections [i].baseOffset;
407 return res >= ctx->size ? INVALID_OFFSET : res;
411 return INVALID_OFFSET;
415 verify_msdos_header (VerifyContext *ctx)
419 ADD_ERROR (ctx, g_strdup ("Not enough space for the MS-DOS header"));
420 if (ctx->data [0] != 0x4d || ctx->data [1] != 0x5a)
421 ADD_ERROR (ctx, g_strdup ("Invalid MS-DOS watermark"));
422 lfanew = pe_signature_offset (ctx);
423 if (lfanew > ctx->size - 4)
424 ADD_ERROR (ctx, g_strdup ("MS-DOS lfanew offset points to outside of the file"));
428 verify_pe_header (VerifyContext *ctx)
430 guint32 offset = pe_signature_offset (ctx);
431 const char *pe_header = ctx->data + offset;
432 if (pe_header [0] != 'P' || pe_header [1] != 'E' ||pe_header [2] != 0 ||pe_header [3] != 0)
433 ADD_ERROR (ctx, g_strdup ("Invalid PE header watermark"));
437 if (offset > ctx->size - 20)
438 ADD_ERROR (ctx, g_strdup ("File with truncated pe header"));
439 if (read16 (pe_header) != 0x14c)
440 ADD_ERROR (ctx, g_strdup ("Invalid PE header Machine value"));
444 verify_pe_optional_header (VerifyContext *ctx)
446 guint32 offset = pe_header_offset (ctx);
447 guint32 header_size, file_alignment;
448 const char *pe_header = ctx->data + offset;
449 const char *pe_optional_header = pe_header + 20;
451 header_size = read16 (pe_header + 16);
454 if (header_size < 2) /*must be at least 2 or we won't be able to read magic*/
455 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
457 if (offset > ctx->size - header_size || header_size > ctx->size)
458 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
460 if (read16 (pe_optional_header) == 0x10b) {
461 if (header_size != 224)
462 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header size %d", header_size));
464 /* LAMESPEC MS plays around this value and ignore it during validation
465 if (read32 (pe_optional_header + 28) != 0x400000)
466 ADD_ERROR (ctx, g_strdup_printf ("Invalid Image base %x", read32 (pe_optional_header + 28)));*/
467 if (read32 (pe_optional_header + 32) != 0x2000)
468 ADD_ERROR (ctx, g_strdup_printf ("Invalid Section Aligmnent %x", read32 (pe_optional_header + 32)));
469 file_alignment = read32 (pe_optional_header + 36);
470 if (file_alignment != 0x200 && file_alignment != 0x1000)
471 ADD_ERROR (ctx, g_strdup_printf ("Invalid file Aligmnent %x", file_alignment));
472 /* All the junk in the middle is irrelevant, specially for mono. */
473 if (read32 (pe_optional_header + 92) > 0x10)
474 ADD_ERROR (ctx, g_strdup_printf ("Too many data directories %x", read32 (pe_optional_header + 92)));
476 if (read16 (pe_optional_header) == 0x20B)
477 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle PE32+"));
479 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header magic %d", read16 (pe_optional_header)));
484 load_section_table (VerifyContext *ctx)
487 SectionHeader *sections;
488 guint32 offset = pe_header_offset (ctx);
489 const char *ptr = ctx->data + offset;
490 guint16 num_sections = ctx->section_count = read16 (ptr + 2);
492 offset += 244;/*FIXME, this constant is different under PE32+*/
495 if (num_sections * 40 > ctx->size - offset)
496 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
498 sections = ctx->sections = g_new0 (SectionHeader, num_sections);
499 for (i = 0; i < num_sections; ++i) {
500 sections [i].size = read32 (ptr + 8);
501 sections [i].baseRVA = read32 (ptr + 12);
502 sections [i].baseOffset = read32 (ptr + 20);
503 sections [i].rellocationsRVA = read32 (ptr + 24);
504 sections [i].numberOfRelocations = read16 (ptr + 32);
508 ptr = ctx->data + offset; /*reset it to the beggining*/
509 for (i = 0; i < num_sections; ++i) {
510 guint32 raw_size, flags;
511 if (sections [i].baseOffset == 0)
512 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with intialized data only"));
513 if (sections [i].baseOffset >= ctx->size)
514 ADD_ERROR (ctx, g_strdup_printf ("Invalid PointerToRawData %x points beyond EOF", sections [i].baseOffset));
515 if (sections [i].size > ctx->size - sections [i].baseOffset)
516 ADD_ERROR (ctx, g_strdup ("Invalid VirtualSize points beyond EOF"));
518 raw_size = read32 (ptr + 16);
519 if (raw_size < sections [i].size)
520 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with SizeOfRawData < VirtualSize"));
522 if (raw_size > ctx->size - sections [i].baseOffset)
523 ADD_ERROR (ctx, g_strdup_printf ("Invalid SizeOfRawData %x points beyond EOF", raw_size));
525 if (sections [i].rellocationsRVA || sections [i].numberOfRelocations)
526 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't handle section relocation"));
528 flags = read32 (ptr + 36);
529 /*TODO 0xFE0000E0 is all flags from cil-coff.h OR'd. Make it a less magical number*/
530 if (flags == 0 || (flags & ~0xFE0000E0) != 0)
531 ADD_ERROR (ctx, g_strdup_printf ("Invalid section flags %x", flags));
538 is_valid_data_directory (int i)
540 /*LAMESPEC 4 == certificate 6 == debug, MS uses both*/
541 return i == 1 || i == 2 || i == 5 || i == 12 || i == 14 || i == 4 || i == 6;
545 load_data_directories (VerifyContext *ctx)
547 guint32 offset = pe_header_offset (ctx) + 116; /*FIXME, this constant is different under PE32+*/
548 const char *ptr = ctx->data + offset;
551 for (i = 0; i < 16; ++i) {
552 guint32 rva = read32 (ptr);
553 guint32 size = read32 (ptr + 4);
555 /*LAMESPEC the authenticode data directory format is different. We don't support CAS, so lets ignore for now.*/
556 if (i == CERTIFICATE_TABLE_IDX) {
560 if ((rva != 0 || size != 0) && !is_valid_data_directory (i))
561 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d", i));
563 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
564 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d rva/size pair %x/%x", i, rva, size));
566 ctx->data_directories [i].rva = rva;
567 ctx->data_directories [i].size = size;
568 ctx->data_directories [i].translated_offset = translate_rva (ctx, rva);
574 #define SIZE_OF_MSCOREE (sizeof ("mscoree.dll"))
576 #define SIZE_OF_CORMAIN (sizeof ("_CorExeMain"))
579 verify_hint_name_table (VerifyContext *ctx, guint32 import_rva, const char *table_name)
582 guint32 hint_table_rva;
584 import_rva = translate_rva (ctx, import_rva);
585 g_assert (import_rva != INVALID_OFFSET);
587 hint_table_rva = read32 (ctx->data + import_rva);
588 if (!bounds_check_virtual_address (ctx, hint_table_rva, SIZE_OF_CORMAIN + 2))
589 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint/Name rva %d for %s", hint_table_rva, table_name));
591 hint_table_rva = translate_rva (ctx, hint_table_rva);
592 g_assert (hint_table_rva != INVALID_OFFSET);
593 ptr = ctx->data + hint_table_rva + 2;
595 if (memcmp ("_CorExeMain", ptr, SIZE_OF_CORMAIN) && memcmp ("_CorDllMain", ptr, SIZE_OF_CORMAIN)) {
596 char name[SIZE_OF_CORMAIN];
597 memcpy (name, ptr, SIZE_OF_CORMAIN);
598 name [SIZE_OF_CORMAIN - 1] = 0;
599 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint / Name: '%s'", name));
604 verify_import_table (VerifyContext *ctx)
606 DataDirectory it = ctx->data_directories [IMPORT_TABLE_IDX];
607 guint32 offset = it.translated_offset;
608 const char *ptr = ctx->data + offset;
609 guint32 name_rva, ilt_rva, iat_rva;
611 g_assert (offset != INVALID_OFFSET);
614 ADD_ERROR (ctx, g_strdup_printf ("Import table size %d is smaller than 40", it.size));
616 ilt_rva = read32 (ptr);
617 if (ilt_rva && !bounds_check_virtual_address (ctx, ilt_rva, 8))
618 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Lookup Table rva %x", ilt_rva));
620 name_rva = read32 (ptr + 12);
621 if (name_rva && !bounds_check_virtual_address (ctx, name_rva, SIZE_OF_MSCOREE))
622 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name rva %x", name_rva));
624 iat_rva = read32 (ptr + 16);
626 if (!bounds_check_virtual_address (ctx, iat_rva, 8))
627 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Address Table rva %x", iat_rva));
629 if (iat_rva != ctx->data_directories [IAT_IDX].rva)
630 ADD_ERROR (ctx, g_strdup_printf ("Import Address Table rva %x different from data directory entry %x", read32 (ptr + 16), ctx->data_directories [IAT_IDX].rva));
634 name_rva = translate_rva (ctx, name_rva);
635 g_assert (name_rva != INVALID_OFFSET);
636 ptr = ctx->data + name_rva;
638 if (memcmp ("mscoree.dll", ptr, SIZE_OF_MSCOREE)) {
639 char name[SIZE_OF_MSCOREE];
640 memcpy (name, ptr, SIZE_OF_MSCOREE);
641 name [SIZE_OF_MSCOREE - 1] = 0;
642 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name: '%s'", name));
647 verify_hint_name_table (ctx, ilt_rva, "Import Lookup Table");
652 verify_hint_name_table (ctx, iat_rva, "Import Address Table");
656 verify_resources_table (VerifyContext *ctx)
658 DataDirectory it = ctx->data_directories [RESOURCE_TABLE_IDX];
660 guint16 named_entries, id_entries;
661 const char *ptr, *root, *end;
667 ADD_ERROR (ctx, g_strdup_printf ("Resource section is too small, must be at least 16 bytes long but it's %d long", it.size));
669 offset = it.translated_offset;
670 root = ptr = ctx->data + offset;
671 end = root + it.size;
673 g_assert (offset != INVALID_OFFSET);
675 named_entries = read16 (ptr + 12);
676 id_entries = read16 (ptr + 14);
678 if ((named_entries + id_entries) * 8 + 16 > it.size)
679 ADD_ERROR (ctx, g_strdup_printf ("Resource section is too small, the number of entries (%d) doesn't fit on it's size %d", named_entries + id_entries, it.size));
681 /* XXX at least one unmanaged resource is added due to a call to AssemblyBuilder::DefineVersionInfoResource ()
682 if (named_entries || id_entries)
683 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support full verification of PECOFF resources"));
687 /*----------nothing from here on can use data_directory---*/
690 get_data_dir (VerifyContext *ctx, int idx)
692 MonoCLIImageInfo *iinfo = ctx->image->image_info;
693 MonoPEDirEntry *entry= &iinfo->cli_header.datadir.pe_export_table;
697 res.rva = entry->rva;
698 res.size = entry->size;
699 res.translated_offset = translate_rva (ctx, res.rva);
704 verify_cli_header (VerifyContext *ctx)
706 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
712 ADD_ERROR (ctx, g_strdup_printf ("CLI header missing"));
715 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size in data directory %d must be 72", it.size));
717 offset = it.translated_offset;
718 ptr = ctx->data + offset;
720 g_assert (offset != INVALID_OFFSET);
722 if (read16 (ptr) != 72)
723 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size %d must be 72", read16 (ptr)));
725 if (!bounds_check_virtual_address (ctx, read32 (ptr + 8), read32 (ptr + 12)))
726 ADD_ERROR (ctx, g_strdup_printf ("Invalid medatata section rva/size pair %x/%x", read32 (ptr + 8), read32 (ptr + 12)));
729 if (!read32 (ptr + 8) || !read32 (ptr + 12))
730 ADD_ERROR (ctx, g_strdup_printf ("Missing medatata section in the CLI header"));
732 if ((read32 (ptr + 16) & ~0x0001000B) != 0)
733 ADD_ERROR (ctx, g_strdup_printf ("Invalid CLI header flags"));
736 for (i = 0; i < 6; ++i) {
737 guint32 rva = read32 (ptr);
738 guint32 size = read32 (ptr + 4);
740 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
741 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli section %i rva/size pair %x/%x", i, rva, size));
746 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't support cli header section %d", i));
751 pad4 (guint32 offset)
753 if (offset & 0x3) //pad to the next 4 byte boundary
754 offset = (offset & ~0x3) + 4;
759 verify_metadata_header (VerifyContext *ctx)
762 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
763 guint32 offset, section_count;
766 offset = it.translated_offset;
767 ptr = ctx->data + offset;
768 g_assert (offset != INVALID_OFFSET);
770 //build a directory entry for the metadata root
772 it.rva = read32 (ptr);
774 it.size = read32 (ptr);
775 it.translated_offset = offset = translate_rva (ctx, it.rva);
777 ptr = ctx->data + offset;
778 g_assert (offset != INVALID_OFFSET);
781 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small %d (at least 20 bytes required for initial decoding)", it.size));
783 if (read32 (ptr) != 0x424A5342)
784 ADD_ERROR (ctx, g_strdup_printf ("Invalid metadata signature, expected 0x424A5342 but got %08x", read32 (ptr)));
786 offset = pad4 (offset + 16 + read32 (ptr + 12));
788 if (!bounds_check_datadir (&it, offset, 4))
789 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small %d (at least %d bytes required for flags decoding)", it.size, offset + 4 - it.translated_offset));
791 ptr = ctx->data + offset; //move to streams header
793 section_count = read16 (ptr + 2);
794 if (section_count < 2)
795 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section must have at least 2 streams (#~ and #GUID)"));
800 for (i = 0; i < section_count; ++i) {
801 guint32 stream_off, stream_size;
802 int string_size, stream_idx;
804 if (!bounds_check_datadir (&it, offset, 8))
805 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small for initial decode of stream header %d, missing %d bytes", i, offset + 9 - it.translated_offset));
807 stream_off = it.translated_offset + read32 (ptr);
808 stream_size = read32 (ptr + 4);
810 if (!bounds_check_datadir (&it, stream_off, stream_size))
811 ADD_ERROR (ctx, g_strdup_printf ("Invalid stream header %d offset/size pair %x/%x", 0, stream_off, stream_size));
816 for (string_size = 0; string_size < 32; ++string_size) {
817 if (!bounds_check_datadir (&it, offset++, 1))
818 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small to decode stream header %d name", i));
819 if (!ptr [string_size])
823 if (ptr [string_size])
824 ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d name larger than 32 bytes", i));
826 if (!strncmp ("#Strings", ptr, 9))
827 stream_idx = STRINGS_STREAM;
828 else if (!strncmp ("#US", ptr, 4))
829 stream_idx = USER_STRINGS_STREAM;
830 else if (!strncmp ("#Blob", ptr, 6))
831 stream_idx = BLOB_STREAM;
832 else if (!strncmp ("#GUID", ptr, 6))
833 stream_idx = GUID_STREAM;
834 else if (!strncmp ("#~", ptr, 3))
835 stream_idx = TILDE_STREAM;
837 ADD_WARNING (ctx, g_strdup_printf ("Metadata stream header %d invalid name %s", i, ptr));
838 offset = pad4 (offset);
839 ptr = ctx->data + offset;
843 if (ctx->metadata_streams [stream_idx].offset != 0)
844 ADD_ERROR (ctx, g_strdup_printf ("Duplicated metadata stream header %s", ptr));
846 ctx->metadata_streams [stream_idx].offset = stream_off;
847 ctx->metadata_streams [stream_idx].size = stream_size;
849 offset = pad4 (offset);
850 ptr = ctx->data + offset;
853 if (!ctx->metadata_streams [TILDE_STREAM].size)
854 ADD_ERROR (ctx, g_strdup_printf ("Metadata #~ stream missing"));
855 if (!ctx->metadata_streams [GUID_STREAM].size)
856 ADD_ERROR (ctx, g_strdup_printf ("Metadata guid stream missing"));
860 verify_tables_schema (VerifyContext *ctx)
862 OffsetAndSize tables_area = ctx->metadata_streams [TILDE_STREAM];
863 unsigned offset = tables_area.offset;
864 const char *ptr = ctx->data + offset;
865 guint64 valid_tables;
869 if (tables_area.size < 24)
870 ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for initial decoding (requires 24 bytes)", tables_area.size));
872 if (ptr [4] != 2 && ptr [4] != 1)
873 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata major version %d, expected 2", ptr [4]));
875 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata minor version %d, expected 0", ptr [5]));
877 if ((ptr [6] & ~0x7) != 0)
878 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata heap sizes 0x%02x, only bits 0, 1 and 2 can be set", ((unsigned char *) ptr) [6]));
880 valid_tables = read64 (ptr + 8);
882 for (i = 0; i < 64; ++i) {
883 if (!(valid_tables & ((guint64)1 << i)))
886 /*MS Extensions: 0x3 0x5 0x7 0x13 0x16
887 Unused: 0x1E 0x1F 0x2D-0x3F
888 We don't care about the MS extensions.*/
889 if (i == 0x3 || i == 0x5 || i == 0x7 || i == 0x13 || i == 0x16)
890 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support MS specific table %x", i));
891 if (i == 0x1E || i == 0x1F || i >= 0x2D)
892 ADD_ERROR (ctx, g_strdup_printf ("Invalid table %x", i));
896 if (tables_area.size < 24 + count * 4)
897 ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for decoding row counts (requires %d bytes)", tables_area.size, 24 + count * 4));
900 for (i = 0; i < 64; ++i) {
901 if (valid_tables & ((guint64)1 << i)) {
902 guint32 row_count = read32 (ptr);
903 if (row_count > (1 << 24) - 1)
904 ADD_ERROR (ctx, g_strdup_printf ("Invalid Table %d row count: %d. Mono only supports 16777215 rows", i, row_count));
910 /*----------nothing from here on can use data_directory or metadata_streams ---*/
913 get_col_offset (VerifyContext *ctx, int table, int column)
915 guint32 bitfield = ctx->image->tables [table].size_bitfield;
919 offset += mono_metadata_table_size (bitfield, column);
925 get_col_size (VerifyContext *ctx, int table, int column)
927 return mono_metadata_table_size (ctx->image->tables [table].size_bitfield, column);
931 get_metadata_stream (VerifyContext *ctx, MonoStreamHeader *header)
934 res.offset = header->data - ctx->data;
935 res.size = header->size;
941 is_valid_string_full_with_image (MonoImage *image, guint32 offset, gboolean allow_empty)
943 guint32 heap_offset = (char*)image->heap_strings.data - image->raw_data;
944 guint32 heap_size = image->heap_strings.size;
947 const char *data = image->raw_data + heap_offset;
949 if (offset >= heap_size)
951 if (CHECK_ADDP_OVERFLOW_UN (data, offset))
954 if (!mono_utf8_validate_and_len_with_bounds (data + offset, heap_size - offset, &length, NULL))
956 return allow_empty || length > 0;
961 is_valid_string_full (VerifyContext *ctx, guint32 offset, gboolean allow_empty)
963 return is_valid_string_full_with_image (ctx->image, offset, allow_empty);
967 is_valid_string (VerifyContext *ctx, guint32 offset)
969 return is_valid_string_full (ctx, offset, TRUE);
973 is_valid_non_empty_string (VerifyContext *ctx, guint32 offset)
975 return is_valid_string_full (ctx, offset, FALSE);
979 is_valid_guid (VerifyContext *ctx, guint32 offset)
981 OffsetAndSize guids = get_metadata_stream (ctx, &ctx->image->heap_guid);
982 return guids.size >= 8 && guids.size - 8 >= offset;
986 get_coded_index_token (int token_kind, guint32 coded_token)
988 guint32 bits = coded_index_desc [token_kind];
989 return coded_token >> bits;
993 get_coded_index_table (int kind, guint32 coded_token)
995 guint32 idx, bits = coded_index_desc [kind];
997 idx = coded_token & ((1 << bits) - 1);
998 return coded_index_desc [kind + idx];
1002 make_coded_token (int kind, guint32 table, guint32 table_idx)
1004 guint32 bits = coded_index_desc [kind++];
1005 guint32 tables = coded_index_desc [kind++];
1007 for (i = 0; i < tables; ++i) {
1008 if (coded_index_desc [kind++] == table)
1009 return ((table_idx + 1) << bits) | i;
1011 g_assert_not_reached ();
1016 is_valid_coded_index_with_image (MonoImage *image, int token_kind, guint32 coded_token)
1018 guint32 bits = coded_index_desc [token_kind++];
1019 guint32 table_count = coded_index_desc [token_kind++];
1020 guint32 table = coded_token & ((1 << bits) - 1);
1021 guint32 token = coded_token >> bits;
1023 if (table >= table_count)
1026 /*token_kind points to the first table idx*/
1027 table = coded_index_desc [token_kind + table];
1029 if (table == INVALID_TABLE)
1031 return token <= image->tables [table].rows;
1035 is_valid_coded_index (VerifyContext *ctx, int token_kind, guint32 coded_token)
1037 return is_valid_coded_index_with_image (ctx->image, token_kind, coded_token);
1044 MonoTableInfo *table;
1048 token_locator (const void *a, const void *b)
1050 RowLocator *loc = (RowLocator *)a;
1051 unsigned const char *row = (unsigned const char *)b;
1052 guint32 token = loc->col_size == 2 ? read16 (row + loc->col_offset) : read32 (row + loc->col_offset);
1054 VERIFIER_DEBUG ( printf ("\tfound token %x at idx %d\n", token, ((const char*)row - loc->table->base) / loc->table->row_size) );
1055 return (int)loc->token - (int)token;
1059 search_sorted_table (VerifyContext *ctx, int table, int column, guint32 coded_token)
1061 MonoTableInfo *tinfo = &ctx->image->tables [table];
1063 const char *res, *base;
1064 locator.token = coded_token;
1065 locator.col_offset = get_col_offset (ctx, table, column);
1066 locator.col_size = get_col_size (ctx, table, column);
1067 locator.table = tinfo;
1071 VERIFIER_DEBUG ( printf ("looking token %x table %d col %d rsize %d roff %d\n", coded_token, table, column, locator.col_size, locator.col_offset) );
1072 res = bsearch (&locator, base, tinfo->rows, tinfo->row_size, token_locator);
1076 return (res - base) / tinfo->row_size;
1079 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1081 get_string_ptr (VerifyContext *ctx, guint offset)
1083 return ctx->image->heap_strings.data + offset;
1086 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1088 string_cmp (VerifyContext *ctx, const char *str, guint offset)
1091 return strcmp (str, "");
1093 return strcmp (str, get_string_ptr (ctx, offset));
1097 mono_verifier_is_corlib (MonoImage *image)
1099 gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ?
1100 TRUE : mono_security_core_clr_is_platform_image (image);
1102 return trusted_location && image->module_name && !strcmp ("mscorlib.dll", image->module_name);
1106 typedef_is_system_object (VerifyContext *ctx, guint32 *data)
1108 return mono_verifier_is_corlib (ctx->image) && !string_cmp (ctx, "System", data [MONO_TYPEDEF_NAMESPACE]) && !string_cmp (ctx, "Object", data [MONO_TYPEDEF_NAME]);
1112 decode_value (const char *_ptr, unsigned available, unsigned *value, unsigned *size)
1115 const unsigned char *ptr = (const unsigned char *)_ptr;
1123 if ((b & 0x80) == 0) {
1126 } else if ((b & 0x40) == 0) {
1130 *value = ((b & 0x3f) << 8 | ptr [1]);
1135 *value = ((b & 0x1f) << 24) |
1145 decode_signature_header (VerifyContext *ctx, guint32 offset, guint32 *size, const char **first_byte)
1147 MonoStreamHeader blob = ctx->image->heap_blob;
1148 guint32 value, enc_size;
1150 if (offset >= blob.size)
1153 if (!decode_value (blob.data + offset, blob.size - offset, &value, &enc_size))
1156 if (CHECK_ADD4_OVERFLOW_UN (offset, enc_size))
1161 if (ADD_IS_GREATER_OR_OVF (offset, value, blob.size))
1165 *first_byte = blob.data + offset;
1170 safe_read (const char **_ptr, const char *limit, unsigned *dest, int size)
1172 const char *ptr = *_ptr;
1173 if (ptr + size > limit)
1177 *dest = *((guint8*)ptr);
1181 *dest = read16 (ptr);
1185 *dest = read32 (ptr);
1194 safe_read_compressed_int (const char **_ptr, const char *limit, unsigned *dest)
1197 const char *ptr = *_ptr;
1198 gboolean res = decode_value (ptr, limit - ptr, dest, &size);
1203 #define safe_read8(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 1)
1204 #define safe_read_cint(VAR, PTR, LIMIT) safe_read_compressed_int (&PTR, LIMIT, &VAR)
1205 #define safe_read16(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 2)
1206 #define safe_read32(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 4)
1209 parse_type (VerifyContext *ctx, const char **_ptr, const char *end);
1212 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged);
1215 parse_custom_mods (VerifyContext *ctx, const char **_ptr, const char *end)
1217 const char *ptr = *_ptr;
1222 if (!safe_read8 (type, ptr, end))
1223 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the type"));
1225 if (type != MONO_TYPE_CMOD_REQD && type != MONO_TYPE_CMOD_OPT) {
1230 if (!safe_read_cint (token, ptr, end))
1231 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the token"));
1233 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1234 FAIL (ctx, g_strdup_printf ("CustomMod: invalid TypeDefOrRef token %x", token));
1242 parse_array_shape (VerifyContext *ctx, const char **_ptr, const char *end)
1244 const char *ptr = *_ptr;
1246 unsigned size, num, i;
1248 if (!safe_read8 (val, ptr, end))
1249 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for Rank"));
1252 FAIL (ctx, g_strdup ("ArrayShape: Invalid shape with zero Rank"));
1254 if (!safe_read_cint (size, ptr, end))
1255 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumSizes"));
1257 for (i = 0; i < size; ++i) {
1258 if (!safe_read_cint (num, ptr, end))
1259 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for Size of rank %d", i + 1));
1262 if (!safe_read_cint (size, ptr, end))
1263 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumLoBounds"));
1265 for (i = 0; i < size; ++i) {
1266 if (!safe_read_cint (num, ptr, end))
1267 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for LoBound of rank %d", i + 1));
1275 parse_generic_inst (VerifyContext *ctx, const char **_ptr, const char *end)
1277 const char *ptr = *_ptr;
1279 unsigned count, token, i;
1281 if (!safe_read8 (type, ptr, end))
1282 FAIL (ctx, g_strdup ("GenericInst: Not enough room for kind"));
1284 if (type != MONO_TYPE_CLASS && type != MONO_TYPE_VALUETYPE)
1285 FAIL (ctx, g_strdup_printf ("GenericInst: Invalid GenericInst kind %x\n", type));
1287 if (!safe_read_cint (token, ptr, end))
1288 FAIL (ctx, g_strdup ("GenericInst: Not enough room for type token"));
1290 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1291 FAIL (ctx, g_strdup_printf ("GenericInst: invalid TypeDefOrRef token %x", token));
1294 if (mono_metadata_token_index (ctx->token) == get_coded_index_token (TYPEDEF_OR_REF_DESC, token) &&
1295 mono_metadata_token_table (ctx->token) == get_coded_index_table (TYPEDEF_OR_REF_DESC, token))
1296 FAIL (ctx, g_strdup_printf ("Type: Recurside generic instance specification (%x). A type signature can't reference itself", ctx->token));
1299 if (!safe_read_cint (count, ptr, end))
1300 FAIL (ctx, g_strdup ("GenericInst: Not enough room for argument count"));
1303 FAIL (ctx, g_strdup ("GenericInst: Zero arguments generic instance"));
1305 for (i = 0; i < count; ++i) {
1306 if (!parse_custom_mods (ctx, &ptr, end))
1307 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1309 if (!parse_type (ctx, &ptr, end))
1310 FAIL (ctx, g_strdup_printf ("GenericInst: invalid generic argument %d", i + 1));
1317 parse_type (VerifyContext *ctx, const char **_ptr, const char *end)
1319 const char *ptr = *_ptr;
1323 if (!safe_read8 (type, ptr, end))
1324 FAIL (ctx, g_strdup ("Type: Not enough room for the type"));
1326 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_PTR) ||
1327 (type >= MONO_TYPE_VALUETYPE && type <= MONO_TYPE_GENERICINST) ||
1328 (type >= MONO_TYPE_I && type <= MONO_TYPE_U) ||
1329 (type >= MONO_TYPE_FNPTR && type <= MONO_TYPE_MVAR)))
1330 FAIL (ctx, g_strdup_printf ("Type: Invalid type kind %x\n", type));
1334 if (!parse_custom_mods (ctx, &ptr, end))
1335 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1337 if (!safe_read8 (type, ptr, end))
1338 FAIL (ctx, g_strdup ("Type: Not enough room to parse the pointer type"));
1340 if (type != MONO_TYPE_VOID) {
1342 if (!parse_type (ctx, &ptr, end))
1343 FAIL (ctx, g_strdup ("Type: Could not parse pointer type"));
1347 case MONO_TYPE_VALUETYPE:
1348 case MONO_TYPE_CLASS:
1349 if (!safe_read_cint (token, ptr, end))
1350 FAIL (ctx, g_strdup ("Type: Not enough room for the type token"));
1352 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1353 FAIL (ctx, g_strdup_printf ("Type: invalid TypeDefOrRef token %x", token));
1355 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, token))
1356 FAIL (ctx, g_strdup_printf ("Type: zero TypeDefOrRef token %x", token));
1358 if (mono_metadata_token_index (ctx->token) == get_coded_index_token (TYPEDEF_OR_REF_DESC, token) &&
1359 mono_metadata_token_table (ctx->token) == get_coded_index_table (TYPEDEF_OR_REF_DESC, token))
1360 FAIL (ctx, g_strdup_printf ("Type: Recursive type specification (%x). A type signature can't reference itself", ctx->token));
1365 case MONO_TYPE_MVAR:
1366 if (!safe_read_cint (token, ptr, end))
1367 FAIL (ctx, g_strdup ("Type: Not enough room for to decode generic argument number"));
1370 case MONO_TYPE_ARRAY:
1371 if (!parse_type (ctx, &ptr, end))
1372 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1373 if (!parse_array_shape (ctx, &ptr, end))
1374 FAIL (ctx, g_strdup ("Type: Could not parse array shape"));
1377 case MONO_TYPE_GENERICINST:
1378 if (!parse_generic_inst (ctx, &ptr, end))
1379 FAIL (ctx, g_strdup ("Type: Could not parse generic inst"));
1382 case MONO_TYPE_FNPTR:
1383 if (!parse_method_signature (ctx, &ptr, end, TRUE, TRUE))
1384 FAIL (ctx, g_strdup ("Type: Could not parse method pointer signature"));
1387 case MONO_TYPE_SZARRAY:
1388 if (!parse_custom_mods (ctx, &ptr, end))
1389 FAIL (ctx, g_strdup ("Type: Failed to parse array element custom attr"));
1390 if (!parse_type (ctx, &ptr, end))
1391 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1399 parse_return_type (VerifyContext *ctx, const char **_ptr, const char *end)
1404 if (!parse_custom_mods (ctx, _ptr, end))
1408 if (!safe_read8 (type, ptr, end))
1409 FAIL (ctx, g_strdup ("ReturnType: Not enough room for the type"));
1411 if (type == MONO_TYPE_VOID || type == MONO_TYPE_TYPEDBYREF) {
1416 //it's a byref, update the cursor ptr
1417 if (type == MONO_TYPE_BYREF)
1420 return parse_type (ctx, _ptr, end);
1424 parse_param (VerifyContext *ctx, const char **_ptr, const char *end)
1429 if (!parse_custom_mods (ctx, _ptr, end))
1433 if (!safe_read8 (type, ptr, end))
1434 FAIL (ctx, g_strdup ("Param: Not enough room for the type"));
1436 if (type == MONO_TYPE_TYPEDBYREF) {
1441 //it's a byref, update the cursor ptr
1442 if (type == MONO_TYPE_BYREF) {
1444 if (!parse_custom_mods (ctx, _ptr, end))
1448 return parse_type (ctx, _ptr, end);
1452 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged)
1455 unsigned param_count = 0, gparam_count = 0, type = 0, i;
1456 const char *ptr = *_ptr;
1457 gboolean saw_sentinel = FALSE;
1459 if (!safe_read8 (cconv, ptr, end))
1460 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the call conv"));
1463 FAIL (ctx, g_strdup ("MethodSig: CallConv has 0x80 set"));
1465 if (allow_unmanaged) {
1466 if ((cconv & 0x0F) > MONO_CALL_VARARG)
1467 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not valid, it's %x", cconv & 0x0F));
1468 } else if ((cconv & 0x0F) != MONO_CALL_DEFAULT && (cconv & 0x0F) != MONO_CALL_VARARG)
1469 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not Default or Vararg, it's %x", cconv & 0x0F));
1471 if ((cconv & 0x10) && !safe_read_cint (gparam_count, ptr, end))
1472 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the generic param count"));
1474 if ((cconv & 0x10) && gparam_count == 0)
1475 FAIL (ctx, g_strdup ("MethodSig: Signature with generics but zero arity"));
1477 if (allow_unmanaged && (cconv & 0x10))
1478 FAIL (ctx, g_strdup ("MethodSig: Standalone signature with generic params"));
1480 if (!safe_read_cint (param_count, ptr, end))
1481 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the param count"));
1483 if (!parse_return_type (ctx, &ptr, end))
1484 FAIL (ctx, g_strdup ("MethodSig: Error parsing return type"));
1486 for (i = 0; i < param_count; ++i) {
1487 if (allow_sentinel) {
1488 if (!safe_read8 (type, ptr, end))
1489 FAIL (ctx, g_strdup_printf ("MethodSig: Not enough room for param %d type", i));
1491 if (type == MONO_TYPE_SENTINEL) {
1492 if ((cconv & 0x0F) != MONO_CALL_VARARG)
1493 FAIL (ctx, g_strdup ("MethodSig: Found sentinel but signature is not vararg"));
1496 FAIL (ctx, g_strdup ("MethodSig: More than one sentinel type"));
1498 saw_sentinel = TRUE;
1504 if (!parse_param (ctx, &ptr, end))
1505 FAIL (ctx, g_strdup_printf ("MethodSig: Error parsing arg %d", i));
1513 parse_property_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1516 unsigned param_count = 0, i;
1517 const char *ptr = *_ptr;
1519 if (!safe_read8 (sig, ptr, end))
1520 FAIL (ctx, g_strdup ("PropertySig: Not enough room for signature"));
1522 if (sig != 0x08 && sig != 0x28)
1523 FAIL (ctx, g_strdup_printf ("PropertySig: Signature is not 0x28 or 0x08: %x", sig));
1525 if (!safe_read_cint (param_count, ptr, end))
1526 FAIL (ctx, g_strdup ("PropertySig: Not enough room for the param count"));
1528 if (!parse_custom_mods (ctx, &ptr, end))
1531 if (!parse_type (ctx, &ptr, end))
1532 FAIL (ctx, g_strdup ("PropertySig: Could not parse property type"));
1534 for (i = 0; i < param_count; ++i) {
1535 if (!parse_custom_mods (ctx, &ptr, end))
1536 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1537 if (!parse_type (ctx, &ptr, end))
1538 FAIL (ctx, g_strdup_printf ("PropertySig: Error parsing arg %d", i));
1546 parse_field (VerifyContext *ctx, const char **_ptr, const char *end)
1548 const char *ptr = *_ptr;
1549 unsigned signature = 0;
1551 if (!safe_read8 (signature, ptr, end))
1552 FAIL (ctx, g_strdup ("Field: Not enough room for field signature"));
1554 if (signature != 0x06)
1555 FAIL (ctx, g_strdup_printf ("Field: Invalid signature 0x%x, must be 6", signature));
1557 if (!parse_custom_mods (ctx, &ptr, end))
1560 if (safe_read8 (signature, ptr, end)) {
1561 if (signature != MONO_TYPE_BYREF)
1566 return parse_type (ctx, _ptr, end);
1570 parse_locals_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1573 unsigned locals_count = 0, i;
1574 const char *ptr = *_ptr;
1576 if (!safe_read8 (sig, ptr, end))
1577 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for signature"));
1580 FAIL (ctx, g_strdup_printf ("LocalsSig: Signature is not 0x28 or 0x08: %x", sig));
1582 if (!safe_read_cint (locals_count, ptr, end))
1583 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for the param count"));
1585 /* LAMEIMPL: MS sometimes generates empty local signatures and its verifier is ok with.
1586 if (locals_count == 0)
1587 FAIL (ctx, g_strdup ("LocalsSig: Signature with zero locals"));
1590 for (i = 0; i < locals_count; ++i) {
1591 if (!safe_read8 (sig, ptr, end))
1592 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1594 while (sig == MONO_TYPE_CMOD_REQD || sig == MONO_TYPE_CMOD_OPT || sig == MONO_TYPE_PINNED) {
1595 if (sig != MONO_TYPE_PINNED && !parse_custom_mods (ctx, &ptr, end))
1596 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1597 if (!safe_read8 (sig, ptr, end))
1598 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1601 if (sig == MONO_TYPE_BYREF) {
1602 if (!safe_read8 (sig, ptr, end))
1603 FAIL (ctx, g_strdup_printf ("Type: Not enough room for byref type for local %d", i));
1604 if (sig == MONO_TYPE_TYPEDBYREF)
1605 FAIL (ctx, g_strdup_printf ("Type: Invalid type typedref& for local %d", i));
1608 if (sig == MONO_TYPE_TYPEDBYREF)
1613 if (!parse_type (ctx, &ptr, end))
1614 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1622 is_valid_field_signature (VerifyContext *ctx, guint32 offset)
1625 unsigned signature = 0;
1626 const char *ptr = NULL, *end;
1628 if (!decode_signature_header (ctx, offset, &size, &ptr))
1629 FAIL (ctx, g_strdup ("FieldSig: Could not decode signature header"));
1632 if (!safe_read8 (signature, ptr, end))
1633 FAIL (ctx, g_strdup ("FieldSig: Not enough room for the signature"));
1636 FAIL (ctx, g_strdup_printf ("FieldSig: Invalid signature %x", signature));
1639 return parse_field (ctx, &ptr, end);
1643 is_valid_method_signature (VerifyContext *ctx, guint32 offset)
1646 const char *ptr = NULL, *end;
1648 if (!decode_signature_header (ctx, offset, &size, &ptr))
1649 FAIL (ctx, g_strdup ("MethodSig: Could not decode signature header"));
1652 return parse_method_signature (ctx, &ptr, end, FALSE, FALSE);
1656 is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
1659 unsigned signature = 0;
1660 const char *ptr = NULL, *end;
1662 if (!decode_signature_header (ctx, offset, &size, &ptr))
1663 FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
1666 if (!safe_read8 (signature, ptr, end))
1667 FAIL (ctx, g_strdup ("MemberRefSig: Not enough room for the call conv"));
1670 if (signature == 0x06)
1671 return parse_field (ctx, &ptr, end);
1673 return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1677 is_valid_cattr_blob (VerifyContext *ctx, guint32 offset)
1680 unsigned prolog = 0;
1681 const char *ptr = NULL, *end;
1686 if (!decode_signature_header (ctx, offset, &size, &ptr))
1687 FAIL (ctx, g_strdup ("CustomAttribute: Could not decode signature header"));
1690 if (!safe_read16 (prolog, ptr, end))
1691 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1694 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1700 is_valid_cattr_type (MonoType *type)
1704 if (type->type == MONO_TYPE_OBJECT || (type->type >= MONO_TYPE_BOOLEAN && type->type <= MONO_TYPE_STRING))
1707 if (type->type == MONO_TYPE_VALUETYPE) {
1708 klass = mono_class_from_mono_type (type);
1709 return klass && klass->enumtype;
1712 if (type->type == MONO_TYPE_CLASS)
1713 return mono_class_from_mono_type (type) == mono_defaults.systemtype_class;
1719 is_valid_ser_string_full (VerifyContext *ctx, const char **str_start, guint32 *str_len, const char **_ptr, const char *end)
1722 const char *ptr = *_ptr;
1728 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string size"));
1731 if (*ptr == (char)0xFF) {
1736 if (!safe_read_cint (size, ptr, end))
1737 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string size"));
1739 if (ADDP_IS_GREATER_OR_OVF (ptr, size, end))
1740 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string"));
1750 is_valid_ser_string (VerifyContext *ctx, const char **_ptr, const char *end)
1752 const char *dummy_str;
1754 return is_valid_ser_string_full (ctx, &dummy_str, &dummy_int, _ptr, end);
1758 get_enum_by_encoded_name (VerifyContext *ctx, const char **_ptr, const char *end)
1762 const char *str_start = NULL;
1763 const char *ptr = *_ptr;
1765 guint32 str_len = 0;
1767 if (!is_valid_ser_string_full (ctx, &str_start, &str_len, &ptr, end))
1770 /*NULL or empty string*/
1771 if (str_start == NULL || str_len == 0) {
1772 ADD_ERROR_NO_RETURN (ctx, g_strdup ("CustomAttribute: Null or empty enum name"));
1776 enum_name = g_memdup (str_start, str_len + 1);
1777 enum_name [str_len] = 0;
1778 type = mono_reflection_type_from_name (enum_name, ctx->image);
1780 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute: Invalid enum class %s", enum_name));
1786 klass = mono_class_from_mono_type (type);
1787 if (!klass || !klass->enumtype) {
1788 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute:Class %s::%s is not an enum", klass->name_space, klass->name));
1797 is_valid_fixed_param (VerifyContext *ctx, MonoType *mono_type, const char **_ptr, const char *end)
1800 const char *ptr = *_ptr;
1802 guint32 element_count, i;
1805 klass = mono_type->data.klass;
1806 type = mono_type->type;
1810 case MONO_TYPE_BOOLEAN:
1817 case MONO_TYPE_CHAR:
1831 case MONO_TYPE_STRING:
1833 return is_valid_ser_string (ctx, _ptr, end);
1835 case MONO_TYPE_OBJECT: {
1836 unsigned sub_type = 0;
1837 if (!safe_read8 (sub_type, ptr, end))
1838 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array type"));
1840 if (sub_type >= MONO_TYPE_BOOLEAN && sub_type <= MONO_TYPE_STRING) {
1844 if (sub_type == MONO_TYPE_ENUM) {
1845 klass = get_enum_by_encoded_name (ctx, &ptr, end);
1849 klass = klass->element_class;
1850 type = klass->byval_arg.type;
1853 if (sub_type == 0x50) { /*Type*/
1855 return is_valid_ser_string (ctx, _ptr, end);
1857 if (sub_type == MONO_TYPE_SZARRAY) {
1858 MonoType simple_type = {{0}};
1860 if (!safe_read8 (etype, ptr, end))
1861 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array element type"));
1863 if (etype == MONO_TYPE_ENUM) {
1864 klass = get_enum_by_encoded_name (ctx, &ptr, end);
1867 } else if (etype == 0x50 || etype == MONO_TYPE_CLASS) {
1868 klass = mono_defaults.systemtype_class;
1869 } else if ((etype >= MONO_TYPE_BOOLEAN && etype <= MONO_TYPE_STRING) || etype == 0x51) {
1870 simple_type.type = etype == 0x51 ? MONO_TYPE_OBJECT : etype;
1871 klass = mono_class_from_mono_type (&simple_type);
1873 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype));
1875 type = MONO_TYPE_SZARRAY;
1878 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid boxed object type %x", sub_type));
1882 case MONO_TYPE_CLASS:
1883 if (klass != mono_defaults.systemtype_class)
1884 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid class parameter type %s:%s ",klass->name_space, klass->name));
1886 return is_valid_ser_string (ctx, _ptr, end);
1888 case MONO_TYPE_VALUETYPE:
1889 if (!klass || !klass->enumtype)
1890 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid valuetype parameter expected enum %s:%s ",klass->name_space, klass->name));
1892 klass = klass->element_class;
1893 type = klass->byval_arg.type;
1896 case MONO_TYPE_SZARRAY:
1897 mono_type = &klass->byval_arg;
1898 if (!is_valid_cattr_type (mono_type))
1899 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %s:%s ",klass->name_space, klass->name));
1900 if (!safe_read32 (element_count, ptr, end))
1901 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid class parameter type %s:%s ",klass->name_space, klass->name));
1902 if (element_count == 0xFFFFFFFFu) {
1906 for (i = 0; i < element_count; ++i) {
1907 if (!is_valid_fixed_param (ctx, mono_type, &ptr, end))
1913 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid parameter type %x ", type));
1916 if (ADDP_IS_GREATER_OR_OVF (ptr, elem_size, end))
1917 FAIL (ctx, g_strdup ("CustomAttribute: Not enough space for element"));
1918 *_ptr = ptr + elem_size;
1923 is_valid_cattr_content (VerifyContext *ctx, MonoMethod *ctor, const char *ptr, guint32 size)
1926 unsigned prolog = 0;
1928 MonoMethodSignature *sig;
1933 FAIL (ctx, g_strdup ("CustomAttribute: Invalid constructor"));
1935 sig = mono_method_signature_checked (ctor, &error);
1936 if (!mono_error_ok (&error)) {
1937 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute: Invalid constructor signature %s", mono_error_get_message (&error)));
1938 mono_error_cleanup (&error);
1942 if (sig->sentinelpos != -1 || sig->call_convention == MONO_CALL_VARARG)
1943 FAIL (ctx, g_strdup ("CustomAttribute: Constructor cannot have VARAG signature"));
1947 if (!safe_read16 (prolog, ptr, end))
1948 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1951 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1953 args = sig->param_count;
1954 for (i = 0; i < args; ++i) {
1955 MonoType *arg_type = sig->params [i];
1956 if (!is_valid_fixed_param (ctx, arg_type, &ptr, end))
1960 if (!safe_read16 (num_named, ptr, end))
1961 FAIL (ctx, g_strdup ("CustomAttribute: Not enough space for num_named field"));
1963 for (i = 0; i < num_named; ++i) {
1964 MonoType *type, simple_type = {{0}};
1967 if (!safe_read8 (kind, ptr, end))
1968 FAIL (ctx, g_strdup_printf ("CustomAttribute: Not enough space for named parameter %d kind", i));
1969 if (kind != 0x53 && kind != 0x54)
1970 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid named parameter %d kind %x", i, kind));
1971 if (!safe_read8 (kind, ptr, end))
1972 FAIL (ctx, g_strdup_printf ("CustomAttribute: Not enough space for named parameter %d type", i));
1974 if (kind >= MONO_TYPE_BOOLEAN && kind <= MONO_TYPE_STRING) {
1975 simple_type.type = kind;
1976 type = &simple_type;
1977 } else if (kind == MONO_TYPE_ENUM) {
1978 MonoClass *klass = get_enum_by_encoded_name (ctx, &ptr, end);
1981 type = &klass->byval_arg;
1982 } else if (kind == 0x50) {
1983 type = &mono_defaults.systemtype_class->byval_arg;
1984 } else if (kind == 0x51) {
1985 type = &mono_defaults.object_class->byval_arg;
1986 } else if (kind == MONO_TYPE_SZARRAY) {
1989 if (!safe_read8 (etype, ptr, end))
1990 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array element type"));
1992 if (etype == MONO_TYPE_ENUM) {
1993 klass = get_enum_by_encoded_name (ctx, &ptr, end);
1996 } else if (etype == 0x50 || etype == MONO_TYPE_CLASS) {
1997 klass = mono_defaults.systemtype_class;
1998 } else if ((etype >= MONO_TYPE_BOOLEAN && etype <= MONO_TYPE_STRING) || etype == 0x51) {
1999 simple_type.type = etype == 0x51 ? MONO_TYPE_OBJECT : etype;
2000 klass = mono_class_from_mono_type (&simple_type);
2002 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype));
2004 type = &mono_array_class_get (klass, 1)->byval_arg;
2006 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid named parameter type %x", kind));
2009 if (!is_valid_ser_string (ctx, &ptr, end))
2012 if (!is_valid_fixed_param (ctx, type, &ptr, end))
2021 is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
2023 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2024 //TODO do proper verification
2025 return blob.size >= 1 && blob.size - 1 >= offset;
2029 is_valid_permission_set (VerifyContext *ctx, guint32 offset)
2031 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2032 //TODO do proper verification
2033 return blob.size >= 1 && blob.size - 1 >= offset;
2037 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
2040 unsigned signature = 0;
2041 const char *ptr = NULL, *end;
2043 if (!decode_signature_header (ctx, offset, &size, &ptr))
2044 FAIL (ctx, g_strdup ("StandAloneSig: Could not decode signature header"));
2047 if (!safe_read8 (signature, ptr, end))
2048 FAIL (ctx, g_strdup ("StandAloneSig: Not enough room for the call conv"));
2051 if (signature == 0x07)
2052 return parse_locals_signature (ctx, &ptr, end);
2054 /*F# and managed C++ produce standalonesig for fields even thou the spec doesn't mention it.*/
2055 if (signature == 0x06)
2056 return parse_field (ctx, &ptr, end);
2058 return parse_method_signature (ctx, &ptr, end, TRUE, TRUE);
2062 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
2065 const char *ptr = NULL, *end;
2067 if (!decode_signature_header (ctx, offset, &size, &ptr))
2068 FAIL (ctx, g_strdup ("PropertySig: Could not decode signature header"));
2071 return parse_property_signature (ctx, &ptr, end);
2075 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
2078 const char *ptr = NULL, *end;
2081 if (!decode_signature_header (ctx, offset, &size, &ptr))
2082 FAIL (ctx, g_strdup ("TypeSpec: Could not decode signature header"));
2085 if (!parse_custom_mods (ctx, &ptr, end))
2088 if (!safe_read8 (type, ptr, end))
2089 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for type"));
2091 if (type == MONO_TYPE_BYREF) {
2092 if (!safe_read8 (type, ptr, end))
2093 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for byref type"));
2094 if (type == MONO_TYPE_TYPEDBYREF)
2095 FAIL (ctx, g_strdup ("TypeSpec: Invalid type typedref&"));
2098 if (type == MONO_TYPE_TYPEDBYREF)
2102 return parse_type (ctx, &ptr, end);
2106 is_valid_methodspec_blob (VerifyContext *ctx, guint32 offset)
2109 const char *ptr = NULL, *end;
2111 unsigned count = 0, i;
2113 if (!decode_signature_header (ctx, offset, &size, &ptr))
2114 FAIL (ctx, g_strdup ("MethodSpec: Could not decode signature header"));
2117 if (!safe_read8 (type, ptr, end))
2118 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for call convention"));
2121 FAIL (ctx, g_strdup_printf ("MethodSpec: Invalid call convention 0x%x, expected 0x0A", type));
2123 if (!safe_read_cint (count, ptr, end))
2124 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for parameter count"));
2127 FAIL (ctx, g_strdup ("MethodSpec: Zero generic argument count"));
2129 for (i = 0; i < count; ++i) {
2130 if (!parse_type (ctx, &ptr, end))
2131 FAIL (ctx, g_strdup_printf ("MethodSpec: Could not parse parameter %d", i + 1));
2137 is_valid_blob_object (VerifyContext *ctx, guint32 offset, guint32 minsize)
2139 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2140 guint32 entry_size, bytes;
2142 if (blob.size < offset)
2145 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
2148 if (entry_size < minsize)
2151 if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
2153 entry_size += bytes;
2155 return !ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size);
2159 is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
2161 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2162 guint32 size, entry_size, bytes;
2164 if (blob.size < offset)
2165 FAIL (ctx, g_strdup ("ContantValue: invalid offset"));
2167 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
2168 FAIL (ctx, g_strdup ("ContantValue: not enough space to decode size"));
2170 if (type == MONO_TYPE_STRING) {
2171 //String is encoded as: compressed_int:len len *bytes
2174 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size))
2175 FAIL (ctx, g_strdup_printf ("ContantValue: not enough space for string, required %d but got %d", entry_size * 2, blob.size - offset));
2181 case MONO_TYPE_BOOLEAN:
2186 case MONO_TYPE_CHAR:
2194 case MONO_TYPE_CLASS:
2204 g_assert_not_reached ();
2207 if (size != entry_size)
2208 FAIL (ctx, g_strdup_printf ("ContantValue: Expected size %d but got %d", size, entry_size));
2212 if (ADD_IS_GREATER_OR_OVF (offset, size, blob.size))
2213 FAIL (ctx, g_strdup_printf ("ContantValue: Not enough room for constant, required %d but have %d", size, blob.size - offset));
2215 if (type == MONO_TYPE_CLASS && read32 (ctx->data + blob.offset + offset))
2216 FAIL (ctx, g_strdup_printf ("ContantValue: Type is class but value is not null"));
2220 #define FAT_HEADER_INVALID_FLAGS ~(0x3 | 0x8 | 0x10 | 0xF000)
2221 //only 0x01, 0x40 and 0x80 are allowed
2222 #define SECTION_HEADER_INVALID_FLAGS 0x3E
2225 is_valid_method_header (VerifyContext *ctx, guint32 rva, guint32 *locals_token)
2227 unsigned local_vars_tok, code_size, offset = mono_cli_rva_image_map (ctx->image, rva);
2228 unsigned header = 0;
2229 unsigned fat_header = 0, size = 0, max_stack;
2230 const char *ptr = NULL, *end;
2234 if (offset == INVALID_ADDRESS)
2235 FAIL (ctx, g_strdup ("MethodHeader: Invalid RVA"));
2237 ptr = ctx->data + offset;
2238 end = ctx->data + ctx->size; /*no worries if it spawns multiple sections*/
2240 if (!safe_read8 (header, ptr, end))
2241 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for header"));
2243 switch (header & 0x3) {
2246 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid header type 0x%x", header & 0x3));
2249 if (ADDP_IS_GREATER_OR_OVF (ptr, header, end))
2250 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for method body. Required %d, but only %d is available", header, (int)(end - ptr)));
2255 if (!safe_read16 (fat_header, ptr, end))
2256 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for fat header"));
2258 size = (fat_header >> 12) & 0xF;
2260 FAIL (ctx, g_strdup ("MethodHeader: header size must be 3"));
2262 if (!safe_read16 (max_stack, ptr, end))
2263 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for max stack"));
2265 if (!safe_read32 (code_size, ptr, end))
2266 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for code size"));
2268 if (!safe_read32 (local_vars_tok, ptr, end))
2269 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for local vars tok"));
2271 if (local_vars_tok) {
2272 if (((local_vars_tok >> 24) & 0xFF) != 0x11)
2273 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature table 0x%x", ((local_vars_tok >> 24) & 0xFF)));
2274 if ((local_vars_tok & 0xFFFFFF) > ctx->image->tables [MONO_TABLE_STANDALONESIG].rows)
2275 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature points to invalid row 0x%x", local_vars_tok & 0xFFFFFF));
2276 if (!(local_vars_tok & 0xFFFFFF))
2277 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature with zero index"));
2278 *locals_token = local_vars_tok & 0xFFFFFF;
2281 if (fat_header & FAT_HEADER_INVALID_FLAGS)
2282 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid fat signature flags %x", fat_header & FAT_HEADER_INVALID_FLAGS));
2284 if (ADDP_IS_GREATER_OR_OVF (ptr, code_size, end))
2285 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for code %d", code_size));
2287 if (!(fat_header & 0x08))
2293 unsigned section_header = 0, section_size = 0;
2296 ptr = dword_align (ptr);
2297 if (!safe_read32 (section_header, ptr, end))
2298 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for data section header"));
2300 if (section_header & SECTION_HEADER_INVALID_FLAGS)
2301 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section header flags 0x%x", section_header & SECTION_HEADER_INVALID_FLAGS));
2303 is_fat = (section_header & METHOD_HEADER_SECTION_FAT_FORMAT) != 0;
2304 section_size = (section_header >> 8) & (is_fat ? 0xFFFFFF : 0xFF);
2306 if (section_size < 4)
2307 FAIL (ctx, g_strdup_printf ("MethodHeader: Section size too small"));
2309 if (ADDP_IS_GREATER_OR_OVF (ptr, section_size - 4, end)) /*must be section_size -4 as ptr was incremented by safe_read32*/
2310 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section content %d", section_size));
2312 if (section_header & METHOD_HEADER_SECTION_EHTABLE) {
2313 guint32 i, clauses = section_size / (is_fat ? 24 : 12);
2315 LAMEIMPL: MS emits section_size without accounting for header size.
2316 Mono does as the spec says. section_size is header + section
2317 MS's peverify happily accepts both.
2319 if ((clauses * (is_fat ? 24 : 12) != section_size) && (clauses * (is_fat ? 24 : 12) + 4 != section_size))
2320 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)));
2322 /* only verify the class token is verified as the rest is done by the IL verifier*/
2323 for (i = 0; i < clauses; ++i) {
2324 unsigned flags = *(unsigned char*)ptr;
2325 unsigned class_token = 0;
2326 ptr += (is_fat ? 20 : 8);
2327 if (!safe_read32 (class_token, ptr, end))
2328 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section %d", i));
2329 if (flags == MONO_EXCEPTION_CLAUSE_NONE && class_token) {
2330 guint table = mono_metadata_token_table (class_token);
2331 if (table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPESPEC)
2332 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token table %x", i, table));
2333 if (mono_metadata_token_index (class_token) > ctx->image->tables [table].rows)
2334 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token index %x", i, mono_metadata_token_index (class_token)));
2339 if (!(section_header & METHOD_HEADER_SECTION_MORE_SECTS))
2346 verify_module_table (VerifyContext *ctx)
2348 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
2349 guint32 data [MONO_MODULE_SIZE];
2351 if (table->rows != 1)
2352 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
2354 mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
2356 if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
2357 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
2359 if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
2360 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
2362 if (data [MONO_MODULE_ENC] != 0)
2363 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
2365 if (data [MONO_MODULE_ENCBASE] != 0)
2366 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
2370 verify_typeref_table (VerifyContext *ctx)
2372 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
2376 for (i = 0; i < table->rows; ++i) {
2377 mono_verifier_verify_typeref_row (ctx->image, i, &error);
2378 add_from_mono_error (ctx, &error);
2382 /*bits 9,11,14,15,19,21,24-31 */
2383 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 14) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
2385 verify_typedef_table (VerifyContext *ctx)
2387 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2388 guint32 data [MONO_TYPEDEF_SIZE];
2389 guint32 fieldlist = 1, methodlist = 1, visibility;
2392 if (table->rows == 0)
2393 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2395 for (i = 0; i < table->rows; ++i) {
2396 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2397 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
2398 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
2400 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
2401 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
2403 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
2404 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2406 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
2407 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2409 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) && (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
2410 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
2412 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
2413 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
2415 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
2416 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
2418 if (data [MONO_TYPEDEF_EXTENDS] && !is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
2419 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
2421 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
2422 if ((visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) &&
2423 search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1) == -1)
2424 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d has nested visibility but no rows in the NestedClass table", i));
2426 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
2427 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
2429 if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2430 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
2432 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
2433 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));
2435 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
2436 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
2438 if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
2439 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
2441 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
2442 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));
2444 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
2445 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
2450 verify_typedef_table_full (VerifyContext *ctx)
2452 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2453 guint32 data [MONO_TYPEDEF_SIZE];
2456 if (table->rows == 0)
2457 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2459 for (i = 0; i < table->rows; ++i) {
2460 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2463 /*XXX it's ok if <module> extends object, or anything at all, actually. */
2464 /*if (data [MONO_TYPEDEF_EXTENDS] != 0)
2465 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
2470 if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
2471 if (data [MONO_TYPEDEF_EXTENDS])
2472 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
2474 gboolean is_sys_obj = typedef_is_system_object (ctx, data);
2475 gboolean has_parent = get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]) != 0;
2479 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
2482 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
2490 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
2492 verify_field_table (VerifyContext *ctx)
2494 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2495 guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
2498 module_field_list = (guint32)-1;
2499 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2500 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2501 module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
2504 for (i = 0; i < table->rows; ++i) {
2505 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2506 flags = data [MONO_FIELD_FLAGS];
2508 if (flags & INVALID_FIELD_FLAG_BITS)
2509 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
2511 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)
2512 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
2514 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
2515 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
2517 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
2518 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
2520 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
2521 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
2523 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
2524 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
2525 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
2527 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
2528 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2529 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2531 if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
2532 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2533 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
2535 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
2536 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
2537 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2539 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
2540 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
2542 if (data [MONO_FIELD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_FIELD_SIGNATURE], 1))
2543 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature blob token 0x%x", i, data [MONO_FIELD_SIGNATURE]));
2545 //TODO verify contant flag
2547 if (i + 1 < module_field_list) {
2548 guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
2549 if (!(flags & FIELD_ATTRIBUTE_STATIC))
2550 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
2551 if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
2552 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
2558 verify_field_table_full (VerifyContext *ctx)
2560 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2561 guint32 data [MONO_FIELD_SIZE];
2564 for (i = 0; i < table->rows; ++i) {
2565 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2567 if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
2568 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
2572 /*bits 8,9,10,11,13,14,15*/
2573 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
2575 verify_method_table (VerifyContext *ctx)
2577 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2578 guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
2579 guint32 paramlist = 1;
2580 gboolean is_ctor, is_cctor;
2584 module_method_list = (guint32)-1;
2585 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2586 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2587 module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
2590 for (i = 0; i < table->rows; ++i) {
2591 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2592 rva = data [MONO_METHOD_RVA];
2593 implflags = data [MONO_METHOD_IMPLFLAGS];
2594 flags = data [MONO_METHOD_FLAGS];
2595 access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
2596 code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
2599 if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
2600 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
2603 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
2605 if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
2606 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
2608 name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
2609 is_ctor = !strcmp (".ctor", name);
2610 is_cctor = !strcmp (".cctor", name);
2612 if ((is_ctor || is_cctor) &&
2613 search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
2614 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
2616 if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
2617 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
2619 if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
2620 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
2621 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
2622 if (flags & METHOD_ATTRIBUTE_FINAL)
2623 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and Final", i));
2624 if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
2625 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
2628 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
2629 ADD_WARNING (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
2631 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
2632 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
2634 //XXX no checks against cas stuff 10,11,12,13)
2636 //TODO check iface with .ctor (15,16)
2638 if (i + 1 < module_method_list) {
2639 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2640 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
2641 if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
2642 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
2643 if (!(access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED || access == METHOD_ATTRIBUTE_PUBLIC || access == METHOD_ATTRIBUTE_PRIVATE))
2644 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public or Private", i));
2647 //TODO check valuetype for synchronized
2649 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
2650 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
2652 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
2653 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
2654 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
2655 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2656 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but not Static", i));
2659 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
2660 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2661 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
2663 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
2664 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
2666 //TODO check signature contents
2669 if (flags & METHOD_ATTRIBUTE_ABSTRACT)
2670 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", i));
2671 if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
2672 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
2674 if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2675 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
2678 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2680 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
2681 if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
2682 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
2684 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
2685 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
2687 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
2688 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
2690 if (data [MONO_METHOD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHOD_SIGNATURE], 1))
2691 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature blob token 0x%x", i, data [MONO_METHOD_SIGNATURE]));
2693 if (data [MONO_METHOD_PARAMLIST] == 0)
2694 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
2696 if (data [MONO_METHOD_PARAMLIST] < paramlist)
2697 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));
2699 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
2700 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
2702 paramlist = data [MONO_METHOD_PARAMLIST];
2708 verify_method_table_full (VerifyContext *ctx)
2710 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2711 guint32 data [MONO_METHOD_SIZE], rva, locals_token;
2714 for (i = 0; i < table->rows; ++i) {
2715 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2716 rva = data [MONO_METHOD_RVA];
2718 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
2719 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
2721 if (rva && !is_valid_method_header (ctx, rva, &locals_token))
2722 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
2727 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
2729 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2730 guint32 row = *current_method;
2731 guint32 paramlist, tmp;
2734 paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
2735 while (row < table->rows) {
2736 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
2737 if (tmp > paramlist) {
2738 *current_method = row;
2739 return tmp - paramlist;
2744 /*no more methods, all params apply to the last one*/
2745 *current_method = table->rows;
2750 #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))
2752 verify_param_table (VerifyContext *ctx)
2754 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
2755 guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
2756 gboolean first_param = TRUE;
2759 if (ctx->image->tables [MONO_TABLE_METHOD].rows == 0) {
2760 if (table->rows > 0)
2761 ADD_ERROR (ctx, g_strdup ("Param table has rows while the method table has zero"));
2765 remaining_params = get_next_param_count (ctx, ¤t_method);
2767 for (i = 0; i < table->rows; ++i) {
2768 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
2769 flags = data [MONO_PARAM_FLAGS];
2771 if (flags & INVALID_PARAM_FLAGS_BITS)
2772 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
2774 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
2775 if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
2776 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
2778 if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
2779 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
2782 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)
2783 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
2785 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
2786 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
2788 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
2789 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
2791 first_param = FALSE;
2792 sequence = data [MONO_PARAM_SEQUENCE];
2793 if (--remaining_params == 0) {
2794 remaining_params = get_next_param_count (ctx, ¤t_method);
2801 verify_interfaceimpl_table (VerifyContext *ctx)
2803 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
2804 guint32 data [MONO_INTERFACEIMPL_SIZE];
2807 for (i = 0; i < table->rows; ++i) {
2808 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
2809 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2810 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_INTERFACEIMPL_CLASS]));
2812 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2813 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
2815 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2816 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
2821 verify_memberref_table (VerifyContext *ctx)
2823 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2824 guint32 data [MONO_MEMBERREF_SIZE];
2827 for (i = 0; i < table->rows; ++i) {
2828 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2830 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2831 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
2833 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2834 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
2836 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
2837 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
2839 if (data [MONO_MEMBERREF_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_MEMBERREF_SIGNATURE], 1))
2840 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d invalid signature blob token 0x%x", i, data [MONO_MEMBERREF_SIGNATURE]));
2846 verify_memberref_table_full (VerifyContext *ctx)
2848 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2849 guint32 data [MONO_MEMBERREF_SIZE];
2852 for (i = 0; i < table->rows; ++i) {
2853 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2855 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
2856 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field 0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
2861 verify_constant_table (VerifyContext *ctx)
2863 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
2864 guint32 data [MONO_CONSTANT_SIZE], type;
2867 for (i = 0; i < table->rows; ++i) {
2868 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
2869 type = data [MONO_CONSTANT_TYPE];
2871 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
2872 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
2874 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2875 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
2877 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2878 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
2880 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
2881 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
2886 verify_cattr_table (VerifyContext *ctx)
2888 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2889 guint32 data [MONO_CUSTOM_ATTR_SIZE];
2892 for (i = 0; i < table->rows; ++i) {
2893 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2895 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
2896 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2898 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]))
2899 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Type field 0x%08x", i, data [MONO_CUSTOM_ATTR_TYPE]));
2901 if (data [MONO_CUSTOM_ATTR_VALUE] && !is_valid_blob_object (ctx, data [MONO_CUSTOM_ATTR_VALUE], 0))
2902 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d invalid value blob 0x%x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2907 verify_cattr_table_full (VerifyContext *ctx)
2909 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2912 guint32 data [MONO_CUSTOM_ATTR_SIZE], mtoken, size;
2915 for (i = 0; i < table->rows; ++i) {
2916 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2918 if (!is_valid_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
2919 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2921 mtoken = data [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
2922 switch (data [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
2923 case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
2924 mtoken |= MONO_TOKEN_METHOD_DEF;
2926 case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
2927 mtoken |= MONO_TOKEN_MEMBER_REF;
2930 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute constructor row %d Token 0x%08x", i, data [MONO_CUSTOM_ATTR_TYPE]));
2933 ctor = mono_get_method (ctx->image, mtoken, NULL);
2935 /*This can't fail since this is checked in is_valid_cattr_blob*/
2936 g_assert (decode_signature_header (ctx, data [MONO_CUSTOM_ATTR_VALUE], &size, &ptr));
2938 if (!is_valid_cattr_content (ctx, ctor, ptr, size))
2939 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute content row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2944 verify_field_marshal_table (VerifyContext *ctx)
2946 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2947 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2950 for (i = 0; i < table->rows; ++i) {
2951 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2953 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2954 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
2956 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2957 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
2959 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
2960 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
2962 if (!is_valid_blob_object (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE], 1))
2963 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d invalid NativeType blob 0x%x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2968 verify_field_marshal_table_full (VerifyContext *ctx)
2970 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2971 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2974 for (i = 0; i < table->rows; ++i) {
2975 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2977 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
2978 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2983 verify_decl_security_table (VerifyContext *ctx)
2985 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2986 guint32 data [MONO_DECL_SECURITY_SIZE];
2989 for (i = 0; i < table->rows; ++i) {
2990 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2992 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2993 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
2995 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2996 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
2998 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
2999 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
3004 verify_decl_security_table_full (VerifyContext *ctx)
3006 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
3007 guint32 data [MONO_DECL_SECURITY_SIZE];
3010 for (i = 0; i < table->rows; ++i) {
3011 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
3013 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
3014 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
3019 verify_class_layout_table (VerifyContext *ctx)
3021 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
3022 guint32 data [MONO_CLASS_LAYOUT_SIZE];
3025 for (i = 0; i < table->rows; ++i) {
3026 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
3028 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3029 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
3031 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
3043 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
3049 verify_field_layout_table (VerifyContext *ctx)
3051 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
3052 guint32 data [MONO_FIELD_LAYOUT_SIZE];
3055 for (i = 0; i < table->rows; ++i) {
3056 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
3058 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
3059 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
3064 verify_standalonesig_table (VerifyContext *ctx)
3066 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
3067 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
3070 for (i = 0; i < table->rows; ++i) {
3071 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
3073 if (data [MONO_STAND_ALONE_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_STAND_ALONE_SIGNATURE], 1))
3074 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d invalid signature 0x%x", i, data [MONO_STAND_ALONE_SIGNATURE]));
3079 verify_standalonesig_table_full (VerifyContext *ctx)
3081 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
3082 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
3085 for (i = 0; i < table->rows; ++i) {
3086 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
3088 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
3089 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
3094 verify_eventmap_table (VerifyContext *ctx)
3096 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
3097 guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
3100 for (i = 0; i < table->rows; ++i) {
3101 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
3103 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3104 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
3106 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
3107 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
3109 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
3113 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
3115 verify_event_table (VerifyContext *ctx)
3117 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
3118 guint32 data [MONO_EVENT_SIZE];
3121 for (i = 0; i < table->rows; ++i) {
3122 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
3124 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
3125 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
3127 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
3128 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
3130 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
3131 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
3136 verify_event_table_full (VerifyContext *ctx)
3138 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
3139 MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
3140 guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
3141 gboolean found_add, found_remove;
3144 for (i = 0; i < table->rows; ++i) {
3145 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
3147 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
3148 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
3150 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
3152 //first we move to the first row for this event
3154 if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
3158 //now move forward looking for AddOn and RemoveOn rows
3159 found_add = found_remove = FALSE;
3160 while (idx < sema_table->rows) {
3161 mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
3162 if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
3164 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
3166 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
3167 found_remove = TRUE;
3168 if (found_add && found_remove)
3174 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
3176 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
3181 verify_propertymap_table (VerifyContext *ctx)
3183 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
3184 guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
3187 for (i = 0; i < table->rows; ++i) {
3188 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
3190 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3191 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
3193 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
3194 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
3196 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
3200 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
3202 verify_property_table (VerifyContext *ctx)
3204 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
3205 guint32 data [MONO_PROPERTY_SIZE];
3208 for (i = 0; i < table->rows; ++i) {
3209 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
3211 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
3212 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
3214 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
3215 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
3217 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
3218 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
3220 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
3221 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
3222 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
3228 verify_methodimpl_table (VerifyContext *ctx)
3230 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
3231 guint32 data [MONO_METHODIMPL_SIZE];
3234 for (i = 0; i < table->rows; ++i) {
3235 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
3237 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3238 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
3240 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
3241 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
3243 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
3244 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
3246 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
3247 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
3249 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
3250 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
3255 verify_moduleref_table (VerifyContext *ctx)
3257 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
3258 guint32 data [MONO_MODULEREF_SIZE];
3261 for (i = 0; i < table->rows; ++i) {
3262 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
3264 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
3265 ADD_ERROR (ctx, g_strdup_printf ("Invalid ModuleRef row %d name field %08x", i, data [MONO_MODULEREF_NAME]));
3270 verify_typespec_table (VerifyContext *ctx)
3272 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
3273 guint32 data [MONO_TYPESPEC_SIZE];
3276 for (i = 0; i < table->rows; ++i) {
3277 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
3279 if (data [MONO_TYPESPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_TYPESPEC_SIGNATURE], 1))
3280 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
3285 verify_typespec_table_full (VerifyContext *ctx)
3287 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
3288 guint32 data [MONO_TYPESPEC_SIZE];
3291 for (i = 0; i < table->rows; ++i) {
3292 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
3293 ctx->token = (i + 1) | MONO_TOKEN_TYPE_SPEC;
3294 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
3295 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
3300 #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))
3302 verify_implmap_table (VerifyContext *ctx)
3304 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
3305 guint32 data [MONO_IMPLMAP_SIZE], cconv;
3308 for (i = 0; i < table->rows; ++i) {
3309 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
3311 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
3312 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
3314 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
3315 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
3316 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
3318 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
3319 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
3321 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
3322 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
3324 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
3325 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
3327 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
3328 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
3330 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULEREF].rows)
3331 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
3336 verify_fieldrva_table (VerifyContext *ctx)
3338 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
3339 guint32 data [MONO_FIELD_RVA_SIZE];
3342 for (i = 0; i < table->rows; ++i) {
3343 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
3345 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
3346 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
3348 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
3349 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
3353 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 4) | (1 << 8) | (1 << 14) | (1 << 15))
3355 verify_assembly_table (VerifyContext *ctx)
3357 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
3358 guint32 data [MONO_ASSEMBLY_SIZE], hash;
3361 if (table->rows > 1)
3362 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
3364 for (i = 0; i < table->rows; ++i) {
3365 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
3367 hash = data [MONO_ASSEMBLY_HASH_ALG];
3368 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
3369 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
3371 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
3372 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
3374 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY], 1))
3375 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
3377 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
3378 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
3380 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
3381 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
3385 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~(1)
3387 verify_assemblyref_table (VerifyContext *ctx)
3389 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
3390 guint32 data [MONO_ASSEMBLYREF_SIZE];
3393 for (i = 0; i < table->rows; ++i) {
3394 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
3396 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
3397 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
3399 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY], 1))
3400 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
3402 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
3403 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
3405 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
3406 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
3408 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE], 1))
3409 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
3413 #define INVALID_FILE_FLAGS_BITS ~(1)
3415 verify_file_table (VerifyContext *ctx)
3417 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
3418 guint32 data [MONO_FILE_SIZE];
3421 for (i = 0; i < table->rows; ++i) {
3422 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
3424 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
3425 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
3427 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
3428 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
3430 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE], 1))
3431 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
3435 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
3437 verify_exportedtype_table (VerifyContext *ctx)
3439 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
3440 guint32 data [MONO_EXP_TYPE_SIZE];
3443 for (i = 0; i < table->rows; ++i) {
3444 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
3446 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
3447 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
3449 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
3450 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
3452 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
3453 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
3455 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3456 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
3458 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3459 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
3461 /*nested type can't have a namespace*/
3462 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
3463 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
3467 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
3469 verify_manifest_resource_table (VerifyContext *ctx)
3471 MonoCLIImageInfo *iinfo = ctx->image->image_info;
3472 MonoCLIHeader *ch = &iinfo->cli_cli_header;
3473 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
3474 guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
3477 resources_size = ch->ch_resources.size;
3479 for (i = 0; i < table->rows; ++i) {
3480 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
3482 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
3483 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
3485 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
3486 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
3488 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
3489 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
3491 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
3492 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
3494 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3495 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3497 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
3498 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])));
3500 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
3501 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
3503 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
3504 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
3509 verify_nested_class_table (VerifyContext *ctx)
3511 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3512 guint32 data [MONO_NESTED_CLASS_SIZE];
3515 for (i = 0; i < table->rows; ++i) {
3516 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
3518 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3519 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
3520 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3521 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3522 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
3523 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3527 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
3529 verify_generic_param_table (VerifyContext *ctx)
3531 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
3532 guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
3533 int i, param_number = 0;
3535 for (i = 0; i < table->rows; ++i) {
3536 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
3538 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
3539 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
3541 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
3542 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
3544 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
3545 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
3547 token = data [MONO_GENERICPARAM_OWNER];
3549 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
3550 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
3552 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
3553 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
3555 if (token != last_token) {
3560 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
3561 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));
3568 verify_method_spec_table (VerifyContext *ctx)
3570 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3571 guint32 data [MONO_METHODSPEC_SIZE];
3574 for (i = 0; i < table->rows; ++i) {
3575 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3577 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3578 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
3580 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3581 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
3583 if (data [MONO_METHODSPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHODSPEC_SIGNATURE], 1))
3584 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid signature token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3589 verify_method_spec_table_full (VerifyContext *ctx)
3591 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3592 guint32 data [MONO_METHODSPEC_SIZE];
3595 for (i = 0; i < table->rows; ++i) {
3596 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3598 if (!is_valid_methodspec_blob (ctx, data [MONO_METHODSPEC_SIGNATURE]))
3599 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3604 verify_generic_param_constraint_table (VerifyContext *ctx)
3606 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
3607 guint32 data [MONO_GENPARCONSTRAINT_SIZE];
3610 for (i = 0; i < table->rows; ++i) {
3611 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
3613 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
3614 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_GENPARCONSTRAINT_GENERICPAR]));
3616 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3617 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
3619 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3620 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
3627 const char *name_space;
3628 guint32 resolution_scope;
3632 typedef_hash (gconstpointer _key)
3634 const TypeDefUniqueId *key = _key;
3635 return g_str_hash (key->name) ^ g_str_hash (key->name_space) ^ key->resolution_scope; /*XXX better salt the int key*/
3639 typedef_equals (gconstpointer _a, gconstpointer _b)
3641 const TypeDefUniqueId *a = _a;
3642 const TypeDefUniqueId *b = _b;
3643 return !strcmp (a->name, b->name) && !strcmp (a->name_space, b->name_space) && a->resolution_scope == b->resolution_scope;
3647 verify_typedef_table_global_constraints (VerifyContext *ctx)
3650 guint32 data [MONO_TYPEDEF_SIZE];
3651 guint32 nested_data [MONO_NESTED_CLASS_SIZE];
3652 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
3653 MonoTableInfo *nested_table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3654 GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3656 for (i = 0; i < table->rows; ++i) {
3658 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3659 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
3661 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAME]);
3662 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAMESPACE]);
3663 type->resolution_scope = 0;
3665 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
3666 if (visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) {
3667 int res = search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1);
3668 g_assert (res >= 0);
3670 mono_metadata_decode_row (nested_table, res, nested_data, MONO_NESTED_CLASS_SIZE);
3671 type->resolution_scope = nested_data [MONO_NESTED_CLASS_ENCLOSING];
3674 if (g_hash_table_lookup (unique_types, type)) {
3675 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));
3676 g_hash_table_destroy (unique_types);
3680 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3683 g_hash_table_destroy (unique_types);
3687 verify_typeref_table_global_constraints (VerifyContext *ctx)
3690 guint32 data [MONO_TYPEREF_SIZE];
3691 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
3692 GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3694 for (i = 0; i < table->rows; ++i) {
3695 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3696 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
3698 type->resolution_scope = data [MONO_TYPEREF_SCOPE];
3699 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAME]);
3700 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAMESPACE]);
3702 if (g_hash_table_lookup (unique_types, type)) {
3703 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));
3704 g_hash_table_destroy (unique_types);
3708 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3711 g_hash_table_destroy (unique_types);
3715 verify_tables_data_global_constraints (VerifyContext *ctx)
3717 verify_typedef_table_global_constraints (ctx);
3721 verify_tables_data_global_constraints_full (VerifyContext *ctx)
3723 verify_typeref_table (ctx);
3724 verify_typeref_table_global_constraints (ctx);
3728 verify_tables_data (VerifyContext *ctx)
3730 OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
3731 guint32 size = 0, tables_offset;
3734 for (i = 0; i < 0x2D; ++i) {
3735 MonoTableInfo *table = &ctx->image->tables [i];
3737 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
3738 if (tmp_size < size) {
3746 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
3748 tables_offset = ctx->image->tables_base - ctx->data;
3749 if (!bounds_check_offset (&tables_area, tables_offset, size))
3750 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)));
3752 verify_module_table (ctx);
3754 /*Obfuscators love to place broken stuff in the typeref table
3755 verify_typeref_table (ctx);
3757 verify_typedef_table (ctx);
3759 verify_field_table (ctx);
3761 verify_method_table (ctx);
3763 verify_param_table (ctx);
3765 verify_interfaceimpl_table (ctx);
3767 verify_memberref_table (ctx);
3769 verify_constant_table (ctx);
3771 verify_cattr_table (ctx);
3773 verify_field_marshal_table (ctx);
3775 verify_decl_security_table (ctx);
3777 verify_class_layout_table (ctx);
3779 verify_field_layout_table (ctx);
3781 verify_standalonesig_table (ctx);
3783 verify_eventmap_table (ctx);
3785 verify_event_table (ctx);
3787 verify_propertymap_table (ctx);
3789 verify_property_table (ctx);
3791 verify_methodimpl_table (ctx);
3793 verify_moduleref_table (ctx);
3795 verify_typespec_table (ctx);
3797 verify_implmap_table (ctx);
3799 verify_fieldrva_table (ctx);
3801 verify_assembly_table (ctx);
3803 verify_assemblyref_table (ctx);
3805 verify_file_table (ctx);
3807 verify_exportedtype_table (ctx);
3809 verify_manifest_resource_table (ctx);
3811 verify_nested_class_table (ctx);
3813 verify_generic_param_table (ctx);
3815 verify_method_spec_table (ctx);
3817 verify_generic_param_constraint_table (ctx);
3819 verify_tables_data_global_constraints (ctx);
3823 init_verify_context (VerifyContext *ctx, MonoImage *image, gboolean report_error)
3825 memset (ctx, 0, sizeof (VerifyContext));
3827 ctx->report_error = report_error;
3828 ctx->report_warning = FALSE; //export this setting in the API
3830 ctx->size = image->raw_data_len;
3831 ctx->data = image->raw_data;
3835 cleanup_context (VerifyContext *ctx, GSList **error_list)
3837 g_free (ctx->sections);
3839 *error_list = ctx->errors;
3841 mono_free_verify_list (ctx->errors);
3846 cleanup_context_checked (VerifyContext *ctx, MonoError *error)
3848 g_free (ctx->sections);
3850 MonoVerifyInfo *info = ctx->errors->data;
3851 mono_error_set_bad_image (error, ctx->image, "%s", info->message);
3852 mono_free_verify_list (ctx->errors);
3858 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3862 if (!mono_verifier_is_enabled_for_image (image))
3865 init_verify_context (&ctx, image, error_list != NULL);
3866 ctx.stage = STAGE_PE;
3868 verify_msdos_header (&ctx);
3870 verify_pe_header (&ctx);
3872 verify_pe_optional_header (&ctx);
3874 load_section_table (&ctx);
3876 load_data_directories (&ctx);
3878 verify_import_table (&ctx);
3880 /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
3881 verify_resources_table (&ctx);
3884 return cleanup_context (&ctx, error_list);
3888 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3892 if (!mono_verifier_is_enabled_for_image (image))
3895 init_verify_context (&ctx, image, error_list != NULL);
3896 ctx.stage = STAGE_CLI;
3898 verify_cli_header (&ctx);
3900 verify_metadata_header (&ctx);
3902 verify_tables_schema (&ctx);
3905 return cleanup_context (&ctx, error_list);
3910 * Verifies basic table constraints such as global table invariants (sorting, field monotonicity, etc).
3911 * Other verification checks are meant to be done lazily by the runtime. Those include:
3912 * blob items (signatures, method headers, custom attributes, etc)
3913 * type semantics related
3915 * stuff that should not block other pieces from running such as bad types/methods/fields/etc.
3917 * The whole idea is that if this succeed the runtime is free to play around safely but any complex
3918 * operation still need more checking.
3921 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3925 if (!mono_verifier_is_enabled_for_image (image))
3928 init_verify_context (&ctx, image, error_list != NULL);
3929 ctx.stage = STAGE_TABLES;
3931 verify_tables_data (&ctx);
3933 return cleanup_context (&ctx, error_list);
3938 * Verifies all other constraints.
3941 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3945 if (!mono_verifier_is_enabled_for_image (image))
3948 init_verify_context (&ctx, image, error_list != NULL);
3949 ctx.stage = STAGE_TABLES;
3951 verify_typedef_table_full (&ctx);
3953 verify_field_table_full (&ctx);
3955 verify_method_table_full (&ctx);
3957 verify_memberref_table_full (&ctx);
3959 verify_cattr_table_full (&ctx);
3961 verify_field_marshal_table_full (&ctx);
3963 verify_decl_security_table_full (&ctx);
3965 verify_standalonesig_table_full (&ctx);
3967 verify_event_table_full (&ctx);
3969 verify_typespec_table_full (&ctx);
3971 verify_method_spec_table_full (&ctx);
3973 verify_tables_data_global_constraints_full (&ctx);
3976 return cleanup_context (&ctx, error_list);
3980 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
3984 if (!mono_verifier_is_enabled_for_image (image))
3987 init_verify_context (&ctx, image, error_list != NULL);
3988 ctx.stage = STAGE_TABLES;
3990 is_valid_field_signature (&ctx, offset);
3991 return cleanup_context (&ctx, error_list);
3995 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
3998 guint32 locals_token;
4000 if (!mono_verifier_is_enabled_for_image (image))
4003 init_verify_context (&ctx, image, error_list != NULL);
4004 ctx.stage = STAGE_TABLES;
4006 is_valid_method_header (&ctx, offset, &locals_token);
4008 guint32 sig_offset = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_STANDALONESIG], locals_token - 1, MONO_STAND_ALONE_SIGNATURE);
4009 is_valid_standalonesig_blob (&ctx, sig_offset);
4012 return cleanup_context (&ctx, error_list);
4016 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, MonoError *error)
4020 mono_error_init (error);
4022 if (!mono_verifier_is_enabled_for_image (image))
4025 init_verify_context (&ctx, image, TRUE);
4026 ctx.stage = STAGE_TABLES;
4028 is_valid_method_signature (&ctx, offset);
4029 /*XXX This returns a bad image exception, it might be the case that the right exception is method load.*/
4030 return cleanup_context_checked (&ctx, error);
4034 mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
4038 if (!mono_verifier_is_enabled_for_image (image))
4041 init_verify_context (&ctx, image, error_list != NULL);
4042 ctx.stage = STAGE_TABLES;
4044 is_valid_method_or_field_signature (&ctx, offset);
4045 return cleanup_context (&ctx, error_list);
4049 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
4053 if (!mono_verifier_is_enabled_for_image (image))
4056 init_verify_context (&ctx, image, error_list != NULL);
4057 ctx.stage = STAGE_TABLES;
4059 is_valid_standalonesig_blob (&ctx, offset);
4060 return cleanup_context (&ctx, error_list);
4064 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
4068 if (!mono_verifier_is_enabled_for_image (image))
4071 init_verify_context (&ctx, image, error_list != NULL);
4072 ctx.stage = STAGE_TABLES;
4075 is_valid_typespec_blob (&ctx, offset);
4076 return cleanup_context (&ctx, error_list);
4080 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
4084 if (!mono_verifier_is_enabled_for_image (image))
4087 init_verify_context (&ctx, image, error_list != NULL);
4088 ctx.stage = STAGE_TABLES;
4090 is_valid_methodspec_blob (&ctx, offset);
4091 return cleanup_context (&ctx, error_list);
4095 verify_user_string (VerifyContext *ctx, guint32 offset)
4097 OffsetAndSize heap_us = get_metadata_stream (ctx, &ctx->image->heap_us);
4098 guint32 entry_size, bytes;
4100 if (heap_us.size < offset)
4101 ADD_ERROR (ctx, g_strdup ("User string offset beyond heap_us size"));
4103 if (!decode_value (ctx->data + offset + heap_us.offset, heap_us.size - heap_us.offset, &entry_size, &bytes))
4104 ADD_ERROR (ctx, g_strdup ("Could not decode user string blob size"));
4106 if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
4107 ADD_ERROR (ctx, g_strdup ("User string size overflow"));
4109 entry_size += bytes;
4111 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, heap_us.size))
4112 ADD_ERROR (ctx, g_strdup ("User string oveflow heap_us"));
4116 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
4120 if (!mono_verifier_is_enabled_for_image (image))
4123 init_verify_context (&ctx, image, error_list != NULL);
4124 ctx.stage = STAGE_TABLES;
4126 verify_user_string (&ctx, offset);
4128 return cleanup_context (&ctx, error_list);
4132 mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, GSList **error_list)
4136 if (!mono_verifier_is_enabled_for_image (image))
4139 init_verify_context (&ctx, image, error_list != NULL);
4140 ctx.stage = STAGE_TABLES;
4142 is_valid_cattr_blob (&ctx, offset);
4144 return cleanup_context (&ctx, error_list);
4148 mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, GSList **error_list)
4152 if (!mono_verifier_is_enabled_for_image (image))
4155 init_verify_context (&ctx, image, error_list != NULL);
4156 ctx.stage = STAGE_TABLES;
4158 is_valid_cattr_content (&ctx, ctor, (const char*)data, size);
4160 return cleanup_context (&ctx, error_list);
4164 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
4166 MonoMethodSignature *original_sig;
4167 if (!mono_verifier_is_enabled_for_image (image))
4170 original_sig = mono_method_signature (method);
4171 if (original_sig->call_convention == MONO_CALL_VARARG) {
4172 if (original_sig->hasthis != signature->hasthis)
4174 if (original_sig->call_convention != signature->call_convention)
4176 if (original_sig->explicit_this != signature->explicit_this)
4178 if (original_sig->call_convention != signature->call_convention)
4180 if (original_sig->pinvoke != signature->pinvoke)
4182 if (original_sig->sentinelpos != signature->sentinelpos)
4184 } else if (!mono_metadata_signature_equal (signature, original_sig)) {
4192 mono_verifier_verify_typeref_row (MonoImage *image, guint32 row, MonoError *error)
4194 MonoTableInfo *table = &image->tables [MONO_TABLE_TYPEREF];
4195 guint32 data [MONO_TYPEREF_SIZE];
4197 mono_error_init (error);
4199 if (!mono_verifier_is_enabled_for_image (image))
4202 if (row >= table->rows) {
4203 mono_error_set_bad_image (error, image, "Invalid typeref row %d - table has %d rows", row, table->rows);
4207 mono_metadata_decode_row (table, row, data, MONO_TYPEREF_SIZE);
4208 if (!is_valid_coded_index_with_image (image, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE])) {
4209 mono_error_set_bad_image (error, image, "Invalid typeref row %d coded index 0x%08x", row, data [MONO_TYPEREF_SCOPE]);
4213 if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE])) {
4214 mono_error_set_bad_image (error, image, "The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", row);
4218 if (!data [MONO_TYPEREF_NAME] || !is_valid_string_full_with_image (image, data [MONO_TYPEREF_NAME], FALSE)) {
4219 mono_error_set_bad_image (error, image, "Invalid typeref row %d name token 0x%08x", row, data [MONO_TYPEREF_NAME]);
4223 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_string_full_with_image (image, data [MONO_TYPEREF_NAMESPACE], FALSE)) {
4224 mono_error_set_bad_image (error, image, "Invalid typeref row %d namespace token 0x%08x", row, data [MONO_TYPEREF_NAMESPACE]);
4231 /*Perform additional verification including metadata ones*/
4233 mono_verifier_verify_methodimpl_row (MonoImage *image, guint32 row, MonoError *error)
4235 MonoMethod *declaration, *body;
4236 MonoMethodSignature *body_sig, *decl_sig;
4237 MonoTableInfo *table = &image->tables [MONO_TABLE_METHODIMPL];
4238 guint32 data [MONO_METHODIMPL_SIZE];
4240 mono_error_init (error);
4242 if (!mono_verifier_is_enabled_for_image (image))
4245 if (row >= table->rows) {
4246 mono_error_set_bad_image (error, image, "Invalid methodimpl row %d - table has %d rows", row, table->rows);
4250 mono_metadata_decode_row (table, row, data, MONO_METHODIMPL_SIZE);
4252 body = method_from_method_def_or_ref (image, data [MONO_METHODIMPL_BODY], NULL);
4253 if (mono_loader_get_last_error ()) {
4254 mono_loader_clear_error ();
4255 mono_error_set_bad_image (error, image, "Invalid methodimpl body for row %x", row);
4259 declaration = method_from_method_def_or_ref (image, data [MONO_METHODIMPL_DECLARATION], NULL);
4260 if (mono_loader_get_last_error ()) {
4261 mono_loader_clear_error ();
4262 mono_error_set_bad_image (error, image, "Invalid methodimpl declaration for row %x", row);
4267 mono_class_setup_supertypes (class);
4268 if (!mono_class_has_parent (class, body->klass)) {
4269 mono_error_set_bad_image (error, image, "Invalid methodimpl body doesn't belong to parent for row %x", row);
4273 if (!(body_sig = mono_method_signature_checked (body, error))) {
4277 if (!(decl_sig = mono_method_signature_checked (declaration, error))) {
4281 if (!mono_verifier_is_signature_compatible (decl_sig, body_sig)) {
4282 mono_error_set_bad_image (error, image, "Invalid methodimpl body signature not compatible with declaration row %x", row);
4291 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
4297 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
4303 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
4309 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
4315 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4321 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
4327 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, MonoError *error)
4329 mono_error_init (error);
4334 mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
4340 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
4346 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
4352 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
4358 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
4364 mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, GSList **error_list)
4370 mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, GSList **error_list)
4376 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
4383 mono_verifier_verify_typeref_row (MonoImage *image, guint32 row, MonoError *error)
4385 mono_error_init (error);
4390 mono_verifier_verify_methodimpl_row (MonoImage *image, guint32 row, MonoError *error)
4392 mono_error_init (error);
4396 #endif /* DISABLE_VERIFIER */