[image] Create MonoImageStorage to own the image raw data (#13892)
[mono-project.git] / mono / metadata / metadata-verify.c
blob418f5c3aabad430bb4a5f6e675ff0ac613a1d338
1 /**
2 * \file
3 * Metadata verfication support
5 * Author:
6 * Mono Project (http://www.mono-project.com)
8 * Copyright (C) 2005-2008 Novell, Inc. (http://www.novell.com)
9 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
11 #include <config.h>
12 #include <mono/metadata/exception-internals.h>
13 #include <mono/metadata/object-internals.h>
14 #include <mono/metadata/verify.h>
15 #include <mono/metadata/verify-internals.h>
16 #include <mono/metadata/opcodes.h>
17 #include <mono/metadata/tabledefs.h>
18 #include <mono/metadata/reflection.h>
19 #include <mono/metadata/reflection-internals.h>
20 #include <mono/metadata/debug-helpers.h>
21 #include <mono/metadata/mono-endian.h>
22 #include <mono/metadata/metadata.h>
23 #include <mono/metadata/metadata-internals.h>
24 #include <mono/metadata/class-internals.h>
25 #include <mono/metadata/class-init.h>
26 #include <mono/metadata/tokentype.h>
27 #include <mono/metadata/security-manager.h>
28 #include <mono/metadata/security-core-clr.h>
29 #include <mono/metadata/cil-coff.h>
30 #include <mono/metadata/attrdefs.h>
31 #include <mono/utils/strenc.h>
32 #include <mono/utils/mono-error-internals.h>
33 #include <mono/utils/bsearch.h>
34 #include <string.h>
35 //#include <signal.h>
36 #include <ctype.h>
38 #ifndef DISABLE_VERIFIER
40 TODO add fail fast mode
41 TODO verify the entry point RVA and content.
42 TODO add section relocation support
43 TODO verify the relocation table, since we really don't use, no need so far.
44 TODO do full PECOFF resources verification
45 TODO verify in the CLI header entry point and resources
46 TODO implement null token typeref validation
47 TODO verify table wide invariants for typedef (sorting and uniqueness)
48 TODO implement proper authenticode data directory validation
49 TODO verify properties that require multiple tables to be valid
50 FIXME use subtraction based bounds checking to avoid overflows
51 FIXME get rid of metadata_streams and other fields from VerifyContext
54 #ifdef MONO_VERIFIER_DEBUG
55 #define VERIFIER_DEBUG(code) do { code; } while (0)
56 #else
57 #define VERIFIER_DEBUG(code)
58 #endif
60 #define INVALID_OFFSET ((guint32)-1)
61 #define INVALID_ADDRESS 0xffffffff
63 enum {
64 STAGE_PE,
65 STAGE_CLI,
66 STAGE_TABLES
69 enum {
70 IMPORT_TABLE_IDX = 1,
71 RESOURCE_TABLE_IDX = 2,
72 CERTIFICATE_TABLE_IDX = 4,
73 RELOCATION_TABLE_IDX = 5,
74 IAT_IDX = 12,
75 CLI_HEADER_IDX = 14,
78 enum {
79 STRINGS_STREAM,
80 USER_STRINGS_STREAM,
81 BLOB_STREAM,
82 GUID_STREAM,
83 TILDE_STREAM
87 #define INVALID_TABLE (0xFF)
88 /*format: number of bits, number of tables, tables{n. tables} */
89 const static unsigned char coded_index_desc[] = {
90 #define TYPEDEF_OR_REF_DESC (0)
91 2, /*bits*/
92 3, /*tables*/
93 MONO_TABLE_TYPEDEF,
94 MONO_TABLE_TYPEREF,
95 MONO_TABLE_TYPESPEC,
97 #define HAS_CONSTANT_DESC (TYPEDEF_OR_REF_DESC + 5)
98 2, /*bits*/
99 3, /*tables*/
100 MONO_TABLE_FIELD,
101 MONO_TABLE_PARAM,
102 MONO_TABLE_PROPERTY,
104 #define HAS_CATTR_DESC (HAS_CONSTANT_DESC + 5)
105 5, /*bits*/
106 20, /*tables*/
107 MONO_TABLE_METHOD,
108 MONO_TABLE_FIELD,
109 MONO_TABLE_TYPEREF,
110 MONO_TABLE_TYPEDEF,
111 MONO_TABLE_PARAM,
112 MONO_TABLE_INTERFACEIMPL,
113 MONO_TABLE_MEMBERREF,
114 MONO_TABLE_MODULE,
115 MONO_TABLE_DECLSECURITY,
116 MONO_TABLE_PROPERTY,
117 MONO_TABLE_EVENT,
118 MONO_TABLE_STANDALONESIG,
119 MONO_TABLE_MODULEREF,
120 MONO_TABLE_TYPESPEC,
121 MONO_TABLE_ASSEMBLY,
122 MONO_TABLE_ASSEMBLYREF,
123 MONO_TABLE_FILE,
124 MONO_TABLE_EXPORTEDTYPE,
125 MONO_TABLE_MANIFESTRESOURCE,
126 MONO_TABLE_GENERICPARAM,
128 #define HAS_FIELD_MARSHAL_DESC (HAS_CATTR_DESC + 22)
129 1, /*bits*/
130 2, /*tables*/
131 MONO_TABLE_FIELD,
132 MONO_TABLE_PARAM,
134 #define HAS_DECL_SECURITY_DESC (HAS_FIELD_MARSHAL_DESC + 4)
135 2, /*bits*/
136 3, /*tables*/
137 MONO_TABLE_TYPEDEF,
138 MONO_TABLE_METHOD,
139 MONO_TABLE_ASSEMBLY,
141 #define MEMBERREF_PARENT_DESC (HAS_DECL_SECURITY_DESC + 5)
142 3, /*bits*/
143 5, /*tables*/
144 MONO_TABLE_TYPEDEF,
145 MONO_TABLE_TYPEREF,
146 MONO_TABLE_MODULEREF,
147 MONO_TABLE_METHOD,
148 MONO_TABLE_TYPESPEC,
150 #define HAS_SEMANTICS_DESC (MEMBERREF_PARENT_DESC + 7)
151 1, /*bits*/
152 2, /*tables*/
153 MONO_TABLE_EVENT,
154 MONO_TABLE_PROPERTY,
156 #define METHODDEF_OR_REF_DESC (HAS_SEMANTICS_DESC + 4)
157 1, /*bits*/
158 2, /*tables*/
159 MONO_TABLE_METHOD,
160 MONO_TABLE_MEMBERREF,
162 #define MEMBER_FORWARDED_DESC (METHODDEF_OR_REF_DESC + 4)
163 1, /*bits*/
164 2, /*tables*/
165 MONO_TABLE_FIELD,
166 MONO_TABLE_METHOD,
168 #define IMPLEMENTATION_DESC (MEMBER_FORWARDED_DESC + 4)
169 2, /*bits*/
170 3, /*tables*/
171 MONO_TABLE_FILE,
172 MONO_TABLE_ASSEMBLYREF,
173 MONO_TABLE_EXPORTEDTYPE,
175 #define CATTR_TYPE_DESC (IMPLEMENTATION_DESC + 5)
176 3, /*bits*/
177 5, /*tables*/
178 INVALID_TABLE,
179 INVALID_TABLE,
180 MONO_TABLE_METHOD,
181 MONO_TABLE_MEMBERREF,
182 INVALID_TABLE,
184 #define RES_SCOPE_DESC (CATTR_TYPE_DESC + 7)
185 2, /*bits*/
186 4, /*tables*/
187 MONO_TABLE_MODULE,
188 MONO_TABLE_MODULEREF,
189 MONO_TABLE_ASSEMBLYREF,
190 MONO_TABLE_TYPEREF,
192 #define TYPE_OR_METHODDEF_DESC (RES_SCOPE_DESC + 6)
193 1, /*bits*/
194 2, /*tables*/
195 MONO_TABLE_TYPEDEF,
196 MONO_TABLE_METHOD
199 typedef struct {
200 guint32 rva;
201 guint32 size;
202 guint32 translated_offset;
203 } DataDirectory;
205 typedef struct {
206 guint32 offset;
207 guint32 size;
208 } OffsetAndSize;
210 typedef struct {
211 guint32 baseRVA;
212 guint32 baseOffset;
213 guint32 size;
214 guint32 rellocationsRVA;
215 guint16 numberOfRelocations;
216 } SectionHeader;
218 typedef struct {
219 guint32 row_count;
220 guint32 row_size;
221 guint32 offset;
222 } TableInfo;
224 typedef struct {
225 const char *data;
226 guint32 size, token;
227 GSList *errors;
228 int valid;
229 MonoImage *image;
230 gboolean report_error;
231 gboolean report_warning;
232 int stage;
234 // Mono really only requires 15 here, but verifies the extra is zeroed.
235 DataDirectory data_directories [16];
236 guint32 section_count;
237 SectionHeader *sections;
238 guint pe64; // short name for PE32+; actual PE64 proposal was rejected
240 OffsetAndSize metadata_streams [5]; //offset from begin of the image
241 } VerifyContext;
243 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception) \
244 do { \
245 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
246 vinfo->info.status = __status; \
247 vinfo->info.message = ( __msg); \
248 vinfo->exception_type = (__exception); \
249 (__ctx)->errors = g_slist_prepend ((__ctx)->errors, vinfo); \
250 } while (0)
252 #define ADD_WARNING(__ctx, __msg) \
253 do { \
254 if ((__ctx)->report_warning) { \
255 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_WARNING, MONO_EXCEPTION_INVALID_PROGRAM); \
256 (__ctx)->valid = 0; \
257 return; \
259 } while (0)
261 #define ADD_ERROR_NO_RETURN(__ctx, __msg) \
262 do { \
263 if ((__ctx)->report_error) \
264 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
265 (__ctx)->valid = 0; \
266 } while (0)
268 #define ADD_ERROR(__ctx, __msg) \
269 do { \
270 if ((__ctx)->report_error) \
271 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
272 (__ctx)->valid = 0; \
273 return; \
274 } while (0)
276 #define FAIL(__ctx, __msg) \
277 do { \
278 if ((__ctx)->report_error) \
279 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
280 (__ctx)->valid = 0; \
281 return FALSE; \
282 } while (0)
284 #define CHECK_STATE() do { if (!ctx.valid) goto cleanup; } while (0)
286 #define CHECK_ERROR() do { if (!ctx->valid) return; } while (0)
288 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
289 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
291 #if SIZEOF_VOID_P == 4
292 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
293 #else
294 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
295 #endif
297 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
298 #define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
300 static const char *
301 dword_align (const char *ptr)
303 #if SIZEOF_VOID_P == 8
304 return (const char *) (((guint64) (ptr + 3)) & ~3);
305 #else
306 return (const char *) (((guint32) (ptr + 3)) & ~3);
307 #endif
310 static void
311 add_from_mono_error (VerifyContext *ctx, MonoError *error)
313 if (mono_error_ok (error))
314 return;
316 ADD_ERROR (ctx, g_strdup (mono_error_get_message (error)));
317 mono_error_cleanup (error);
320 static guint32
321 pe_signature_offset (VerifyContext *ctx)
323 return read32 (ctx->data + 0x3c);
326 static guint32
327 pe_header_offset (VerifyContext *ctx)
329 return read32 (ctx->data + 0x3c) + 4;
332 static gboolean
333 bounds_check_virtual_address (VerifyContext *ctx, guint32 rva, guint32 size)
335 int i;
337 if (rva + size < rva) //overflow
338 return FALSE;
340 if (ctx->stage > STAGE_PE) {
341 MonoCLIImageInfo *iinfo = ctx->image->image_info;
342 const int top = iinfo->cli_section_count;
343 MonoSectionTable *tables = iinfo->cli_section_tables;
344 int i;
346 for (i = 0; i < top; i++) {
347 guint32 base = tables->st_virtual_address;
348 guint32 end = base + tables->st_raw_data_size;
350 if (rva >= base && rva + size <= end)
351 return TRUE;
353 /*if ((addr >= tables->st_virtual_address) &&
354 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
356 return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
358 tables++;
360 return FALSE;
363 if (!ctx->sections)
364 return FALSE;
366 for (i = 0; i < ctx->section_count; ++i) {
367 guint32 base = ctx->sections [i].baseRVA;
368 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
369 if (rva >= base && rva + size <= end)
370 return TRUE;
372 return FALSE;
375 static gboolean
376 bounds_check_datadir (DataDirectory *dir, guint32 offset, guint32 size)
378 if (dir->translated_offset > offset)
379 return FALSE;
380 if (dir->size < size)
381 return FALSE;
382 return offset + size <= dir->translated_offset + dir->size;
385 static gboolean
386 bounds_check_offset (OffsetAndSize *off, guint32 offset, guint32 size)
388 if (off->offset > offset)
389 return FALSE;
391 if (off->size < size)
392 return FALSE;
394 return offset + size <= off->offset + off->size;
397 static guint32
398 translate_rva (VerifyContext *ctx, guint32 rva)
400 int i;
402 if (ctx->stage > STAGE_PE)
403 return mono_cli_rva_image_map (ctx->image, rva);
405 if (!ctx->sections)
406 return FALSE;
408 for (i = 0; i < ctx->section_count; ++i) {
409 guint32 base = ctx->sections [i].baseRVA;
410 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
411 if (rva >= base && rva <= end) {
412 guint32 res = (rva - base) + ctx->sections [i].baseOffset;
413 /* double check */
414 return res >= ctx->size ? INVALID_OFFSET : res;
418 return INVALID_OFFSET;
421 static void
422 verify_msdos_header (VerifyContext *ctx)
424 guint32 lfanew;
425 if (ctx->size < 128)
426 ADD_ERROR (ctx, g_strdup ("Not enough space for the MS-DOS header"));
427 if (ctx->data [0] != 0x4d || ctx->data [1] != 0x5a)
428 ADD_ERROR (ctx, g_strdup ("Invalid MS-DOS watermark"));
429 lfanew = pe_signature_offset (ctx);
430 if (lfanew > ctx->size - 4)
431 ADD_ERROR (ctx, g_strdup ("MS-DOS lfanew offset points to outside of the file"));
434 static void
435 verify_pe_header (VerifyContext *ctx)
437 guint32 offset = pe_signature_offset (ctx);
438 const char *pe_header = ctx->data + offset;
439 if (pe_header [0] != 'P' || pe_header [1] != 'E' ||pe_header [2] != 0 ||pe_header [3] != 0)
440 ADD_ERROR (ctx, g_strdup ("Invalid PE header watermark"));
441 pe_header += 4;
442 offset += 4;
444 if (offset > ctx->size - 20)
445 ADD_ERROR (ctx, g_strdup ("File with truncated pe header"));
448 static void
449 verify_pe_optional_header (VerifyContext *ctx)
451 guint32 offset = pe_header_offset (ctx);
452 guint32 header_size, file_alignment;
453 const char *pe_header = ctx->data + offset;
454 const char *pe_optional_header = pe_header + 20;
456 header_size = read16 (pe_header + 16);
457 offset += 20;
459 if (header_size < 2) /*must be at least 2 or we won't be able to read magic*/
460 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
462 if (offset > ctx->size - header_size || header_size > ctx->size)
463 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
465 const guint16 magic = read16 (pe_optional_header);
467 if (magic == 0x20B) {
468 // Some fields are the same location for PE32 and PE32+.
469 // A few are offset by 4, 8, or 12, but we do not use them.
470 // Others are offset by 16.
471 // Some are missing.
472 ctx->pe64 = 16;
473 } else if (magic != 0x10b)
474 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header magic %d", magic));
476 // Much of this is over-verification.
478 // File align and section align do not matter to Mono.
480 // Mono requires at least 15 data directories. More than that are ignored,
481 // except to require zeros in the 16th.
483 // Mono requires at least 216 (or pe64:232) size.
485 /* LAMESPEC MS plays around this value and ignore it during validation
486 if (read32 (pe_optional_header + 28) != 0x400000)
487 ADD_ERROR (ctx, g_strdup_printf ("Invalid Image base %x", read32 (pe_optional_header + 28)));*/
488 if (read32 (pe_optional_header + 32) != 0x2000)
489 ADD_ERROR (ctx, g_strdup_printf ("Invalid Section Aligmnent %x", read32 (pe_optional_header + 32)));
490 file_alignment = read32 (pe_optional_header + 36);
491 if (file_alignment != 0x200 && file_alignment != 0x1000)
492 ADD_ERROR (ctx, g_strdup_printf ("Invalid file Aligmnent %x", file_alignment));
493 /* All the junk in the middle is irrelevant, specially for mono. */
495 if (header_size != 224 + ctx->pe64)
496 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header size %d", header_size));
498 const guint number_of_rvas_and_sizes = read32 (pe_optional_header + 92 + ctx->pe64);
500 // Data directories beyond 15 do not matter to mono.
501 if (number_of_rvas_and_sizes > 0x10)
502 ADD_ERROR (ctx, g_strdup_printf ("Too many data directories %x", number_of_rvas_and_sizes));
505 static void
506 load_section_table (VerifyContext *ctx)
508 int i;
509 SectionHeader *sections;
510 guint32 offset = pe_header_offset (ctx);
511 const char *ptr = ctx->data + offset;
512 guint16 num_sections = ctx->section_count = read16 (ptr + 2);
514 const guint optional_header_size = read16 (ptr + 16);
515 offset += optional_header_size + 20;
516 ptr += optional_header_size + 20;
518 if (num_sections * 40 > ctx->size - offset)
519 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
521 sections = ctx->sections = g_new0 (SectionHeader, num_sections);
522 for (i = 0; i < num_sections; ++i) {
523 sections [i].size = read32 (ptr + 8);
524 sections [i].baseRVA = read32 (ptr + 12);
525 sections [i].baseOffset = read32 (ptr + 20);
526 sections [i].rellocationsRVA = read32 (ptr + 24);
527 sections [i].numberOfRelocations = read16 (ptr + 32);
528 ptr += 40;
531 ptr = ctx->data + offset; /*reset it to the beggining*/
532 for (i = 0; i < num_sections; ++i) {
533 guint32 raw_size, flags;
534 if (sections [i].baseOffset == 0)
535 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with intialized data only"));
536 if (sections [i].baseOffset >= ctx->size)
537 ADD_ERROR (ctx, g_strdup_printf ("Invalid PointerToRawData %x points beyond EOF", sections [i].baseOffset));
538 if (sections [i].size > ctx->size - sections [i].baseOffset)
539 ADD_ERROR (ctx, g_strdup ("Invalid VirtualSize points beyond EOF"));
541 raw_size = read32 (ptr + 16);
542 if (raw_size < sections [i].size)
543 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with SizeOfRawData < VirtualSize"));
545 if (raw_size > ctx->size - sections [i].baseOffset)
546 ADD_ERROR (ctx, g_strdup_printf ("Invalid SizeOfRawData %x points beyond EOF", raw_size));
548 if (sections [i].rellocationsRVA || sections [i].numberOfRelocations)
549 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't handle section relocation"));
551 flags = read32 (ptr + 36);
552 /*TODO 0xFE0000E0 is all flags from cil-coff.h OR'd. Make it a less magical number*/
553 if (flags == 0 || (flags & ~0xFE0000E0) != 0)
554 ADD_ERROR (ctx, g_strdup_printf ("Invalid section flags %x", flags));
556 ptr += 40;
560 static gboolean
561 is_valid_data_directory (int i)
563 /*LAMESPEC 4 == certificate 6 == debug, MS uses both*/
564 return i == 1 || i == 2 || i == 5 || i == 12 || i == 14 || i == 4 || i == 6;
567 static void
568 load_data_directories (VerifyContext *ctx)
570 guint32 offset = pe_header_offset (ctx) + 116 + ctx->pe64;
571 const char *ptr = ctx->data + offset;
572 int i;
574 for (i = 0; i < 16; ++i, ptr += 8) {
575 guint32 rva = read32 (ptr);
576 guint32 size = read32 (ptr + 4);
578 /*LAMESPEC the authenticode data directory format is different. We don't support CAS, so lets ignore for now.*/
579 if (i == CERTIFICATE_TABLE_IDX)
580 continue;
582 if ((rva != 0 || size != 0) && !is_valid_data_directory (i))
583 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d", i));
585 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
586 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d rva/size pair %x/%x", i, rva, size));
588 ctx->data_directories [i].rva = rva;
589 ctx->data_directories [i].size = size;
590 ctx->data_directories [i].translated_offset = translate_rva (ctx, rva);
594 #define SIZE_OF_MSCOREE (sizeof ("mscoree.dll"))
596 #define SIZE_OF_CORMAIN (sizeof ("_CorExeMain"))
598 static void
599 verify_hint_name_table (VerifyContext *ctx, guint32 import_rva, const char *table_name)
601 const char *ptr;
602 guint32 hint_table_rva;
604 import_rva = translate_rva (ctx, import_rva);
605 g_assert (import_rva != INVALID_OFFSET);
607 hint_table_rva = read32 (ctx->data + import_rva);
608 if (!bounds_check_virtual_address (ctx, hint_table_rva, SIZE_OF_CORMAIN + 2))
609 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint/Name rva %d for %s", hint_table_rva, table_name));
611 hint_table_rva = translate_rva (ctx, hint_table_rva);
612 g_assert (hint_table_rva != INVALID_OFFSET);
613 ptr = ctx->data + hint_table_rva + 2;
615 if (memcmp ("_CorExeMain", ptr, SIZE_OF_CORMAIN) && memcmp ("_CorDllMain", ptr, SIZE_OF_CORMAIN))
616 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint / Name: '%s'", ptr));
619 static void
620 verify_import_table (VerifyContext *ctx)
622 DataDirectory it = ctx->data_directories [IMPORT_TABLE_IDX];
623 guint32 offset = it.translated_offset;
624 const char *ptr = ctx->data + offset;
625 guint32 name_rva, ilt_rva, iat_rva;
627 g_assert (offset != INVALID_OFFSET);
629 if (it.size < 40)
630 ADD_ERROR (ctx, g_strdup_printf ("Import table size %d is smaller than 40", it.size));
632 ilt_rva = read32 (ptr);
633 if (ilt_rva && !bounds_check_virtual_address (ctx, ilt_rva, 8))
634 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Lookup Table rva %x", ilt_rva));
636 name_rva = read32 (ptr + 12);
637 if (name_rva && !bounds_check_virtual_address (ctx, name_rva, SIZE_OF_MSCOREE))
638 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name rva %x", name_rva));
640 iat_rva = read32 (ptr + 16);
641 if (iat_rva) {
642 if (!bounds_check_virtual_address (ctx, iat_rva, 8))
643 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Address Table rva %x", iat_rva));
645 if (iat_rva != ctx->data_directories [IAT_IDX].rva)
646 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));
649 if (name_rva) {
650 name_rva = translate_rva (ctx, name_rva);
651 g_assert (name_rva != INVALID_OFFSET);
652 ptr = ctx->data + name_rva;
654 if (memcmp ("mscoree.dll", ptr, SIZE_OF_MSCOREE))
655 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name: '%s'", ptr));
658 if (ilt_rva) {
659 verify_hint_name_table (ctx, ilt_rva, "Import Lookup Table");
660 CHECK_ERROR ();
663 if (iat_rva)
664 verify_hint_name_table (ctx, iat_rva, "Import Address Table");
667 static void
668 verify_resources_table (VerifyContext *ctx)
670 DataDirectory it = ctx->data_directories [RESOURCE_TABLE_IDX];
671 guint32 offset;
672 guint16 named_entries, id_entries;
673 const char *ptr;
675 if (it.rva == 0)
676 return;
678 if (it.size < 16)
679 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));
681 offset = it.translated_offset;
682 ptr = ctx->data + offset;
684 g_assert (offset != INVALID_OFFSET);
686 named_entries = read16 (ptr + 12);
687 id_entries = read16 (ptr + 14);
689 if ((named_entries + id_entries) * 8 + 16 > it.size)
690 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));
692 /* XXX at least one unmanaged resource is added due to a call to AssemblyBuilder::DefineVersionInfoResource ()
693 if (named_entries || id_entries)
694 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support full verification of PECOFF resources"));
698 /*----------nothing from here on can use data_directory---*/
700 static DataDirectory
701 get_data_dir (VerifyContext *ctx, int idx)
703 MonoCLIImageInfo *iinfo = ctx->image->image_info;
704 MonoPEDirEntry *entry= &iinfo->cli_header.datadir.pe_export_table;
705 DataDirectory res;
707 entry += idx;
708 res.rva = entry->rva;
709 res.size = entry->size;
710 res.translated_offset = translate_rva (ctx, res.rva);
711 return res;
714 static void
715 verify_cli_header (VerifyContext *ctx)
717 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
718 guint32 offset;
719 const char *ptr;
720 int i;
722 if (it.rva == 0)
723 ADD_ERROR (ctx, g_strdup_printf ("CLI header missing"));
725 if (it.size != 72)
726 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size in data directory %d must be 72", it.size));
728 offset = it.translated_offset;
729 ptr = ctx->data + offset;
731 g_assert (offset != INVALID_OFFSET);
733 if (read16 (ptr) != 72)
734 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size %d must be 72", read16 (ptr)));
736 if (!bounds_check_virtual_address (ctx, read32 (ptr + 8), read32 (ptr + 12)))
737 ADD_ERROR (ctx, g_strdup_printf ("Invalid medatata section rva/size pair %x/%x", read32 (ptr + 8), read32 (ptr + 12)));
740 if (!read32 (ptr + 8) || !read32 (ptr + 12))
741 ADD_ERROR (ctx, g_strdup_printf ("Missing medatata section in the CLI header"));
743 if ((read32 (ptr + 16) & ~0x0003000B) != 0)
744 ADD_ERROR (ctx, g_strdup_printf ("Invalid CLI header flags"));
746 ptr += 24;
747 for (i = 0; i < 6; ++i) {
748 guint32 rva = read32 (ptr);
749 guint32 size = read32 (ptr + 4);
751 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
752 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli section %i rva/size pair %x/%x", i, rva, size));
754 ptr += 8;
756 if (rva && i > 1)
757 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't support cli header section %d", i));
761 static guint32
762 pad4 (guint32 offset)
764 if (offset & 0x3) //pad to the next 4 byte boundary
765 offset = (offset & ~0x3) + 4;
766 return offset;
769 static void
770 verify_metadata_header (VerifyContext *ctx)
772 int i;
773 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
774 guint32 offset, section_count;
775 const char *ptr;
777 offset = it.translated_offset;
778 ptr = ctx->data + offset;
779 g_assert (offset != INVALID_OFFSET);
781 //build a directory entry for the metadata root
782 ptr += 8;
783 it.rva = read32 (ptr);
784 ptr += 4;
785 it.size = read32 (ptr);
786 it.translated_offset = offset = translate_rva (ctx, it.rva);
788 ptr = ctx->data + offset;
789 g_assert (offset != INVALID_OFFSET);
791 if (it.size < 20)
792 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small %d (at least 20 bytes required for initial decoding)", it.size));
794 if (read32 (ptr) != 0x424A5342)
795 ADD_ERROR (ctx, g_strdup_printf ("Invalid metadata signature, expected 0x424A5342 but got %08x", read32 (ptr)));
797 offset = pad4 (offset + 16 + read32 (ptr + 12));
799 if (!bounds_check_datadir (&it, offset, 4))
800 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));
802 ptr = ctx->data + offset; //move to streams header
804 section_count = read16 (ptr + 2);
805 if (section_count < 2)
806 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section must have at least 2 streams (#~ and #GUID)"));
808 ptr += 4;
809 offset += 4;
811 for (i = 0; i < section_count; ++i) {
812 guint32 stream_off, stream_size;
813 int string_size, stream_idx;
815 if (!bounds_check_datadir (&it, offset, 8))
816 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));
818 stream_off = it.translated_offset + read32 (ptr);
819 stream_size = read32 (ptr + 4);
821 if (!bounds_check_datadir (&it, stream_off, stream_size))
822 ADD_ERROR (ctx, g_strdup_printf ("Invalid stream header %d offset/size pair %x/%x", 0, stream_off, stream_size));
824 ptr += 8;
825 offset += 8;
827 for (string_size = 0; string_size < 32; ++string_size) {
828 if (!bounds_check_datadir (&it, offset++, 1))
829 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small to decode stream header %d name", i));
830 if (!ptr [string_size])
831 break;
834 if (ptr [string_size])
835 ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d name larger than 32 bytes", i));
837 if (!strncmp ("#Strings", ptr, 9))
838 stream_idx = STRINGS_STREAM;
839 else if (!strncmp ("#US", ptr, 4))
840 stream_idx = USER_STRINGS_STREAM;
841 else if (!strncmp ("#Blob", ptr, 6))
842 stream_idx = BLOB_STREAM;
843 else if (!strncmp ("#GUID", ptr, 6))
844 stream_idx = GUID_STREAM;
845 else if (!strncmp ("#~", ptr, 3))
846 stream_idx = TILDE_STREAM;
847 else {
848 ADD_WARNING (ctx, g_strdup_printf ("Metadata stream header %d invalid name %s", i, ptr));
849 offset = pad4 (offset);
850 ptr = ctx->data + offset;
851 continue;
854 if (ctx->metadata_streams [stream_idx].offset != 0)
855 ADD_ERROR (ctx, g_strdup_printf ("Duplicated metadata stream header %s", ptr));
857 ctx->metadata_streams [stream_idx].offset = stream_off;
858 ctx->metadata_streams [stream_idx].size = stream_size;
860 offset = pad4 (offset);
861 ptr = ctx->data + offset;
864 if (!ctx->metadata_streams [TILDE_STREAM].size)
865 ADD_ERROR (ctx, g_strdup_printf ("Metadata #~ stream missing"));
866 if (!ctx->metadata_streams [GUID_STREAM].size)
867 ADD_ERROR (ctx, g_strdup_printf ("Metadata guid stream missing"));
870 static void
871 verify_tables_schema (VerifyContext *ctx)
873 OffsetAndSize tables_area = ctx->metadata_streams [TILDE_STREAM];
874 unsigned offset = tables_area.offset;
875 const char *ptr = ctx->data + offset;
876 guint64 valid_tables;
877 guint32 count;
878 int i;
880 if (tables_area.size < 24)
881 ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for initial decoding (requires 24 bytes)", tables_area.size));
883 if (ptr [4] != 2 && ptr [4] != 1)
884 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata major version %d, expected 2", ptr [4]));
885 if (ptr [5] != 0)
886 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata minor version %d, expected 0", ptr [5]));
888 if ((ptr [6] & ~0x7) != 0)
889 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]));
891 valid_tables = read64 (ptr + 8);
892 count = 0;
893 for (i = 0; i < 64; ++i) {
894 if (!(valid_tables & ((guint64)1 << i)))
895 continue;
897 /*MS Extensions: 0x3 0x5 0x7 0x13 0x16
898 Unused: 0x1E 0x1F 0x2D-0x3F
899 We don't care about the MS extensions.*/
900 if (i == 0x3 || i == 0x5 || i == 0x7 || i == 0x13 || i == 0x16)
901 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support MS specific table %x", i));
902 if (i == 0x1E || i == 0x1F || i >= 0x2D)
903 ADD_ERROR (ctx, g_strdup_printf ("Invalid table %x", i));
904 ++count;
907 if (tables_area.size < 24 + count * 4)
908 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));
909 ptr += 24;
911 for (i = 0; i < 64; ++i) {
912 if (valid_tables & ((guint64)1 << i)) {
913 guint32 row_count = read32 (ptr);
914 if (row_count > (1 << 24) - 1)
915 ADD_ERROR (ctx, g_strdup_printf ("Invalid Table %d row count: %d. Mono only supports 16777215 rows", i, row_count));
916 ptr += 4;
921 /*----------nothing from here on can use data_directory or metadata_streams ---*/
923 static guint32
924 get_col_offset (VerifyContext *ctx, int table, int column)
926 guint32 bitfield = ctx->image->tables [table].size_bitfield;
927 guint32 offset = 0;
929 while (column-- > 0)
930 offset += mono_metadata_table_size (bitfield, column);
932 return offset;
935 static guint32
936 get_col_size (VerifyContext *ctx, int table, int column)
938 return mono_metadata_table_size (ctx->image->tables [table].size_bitfield, column);
941 static OffsetAndSize
942 get_metadata_stream (VerifyContext *ctx, MonoStreamHeader *header)
944 OffsetAndSize res;
945 res.offset = header->data - ctx->data;
946 res.size = header->size;
948 return res;
951 static gboolean
952 is_valid_string_full_with_image (MonoImage *image, guint32 offset, gboolean allow_empty)
954 guint32 heap_offset = (char*)image->heap_strings.data - m_image_get_raw_data (image);
955 guint32 heap_size = image->heap_strings.size;
957 glong length;
958 const char *data = m_image_get_raw_data (image) + heap_offset;
960 if (offset >= heap_size)
961 return FALSE;
962 if (CHECK_ADDP_OVERFLOW_UN (data, offset))
963 return FALSE;
965 if (!mono_utf8_validate_and_len_with_bounds (data + offset, heap_size - offset, &length, NULL))
966 return FALSE;
967 return allow_empty || length > 0;
971 static gboolean
972 is_valid_string_full (VerifyContext *ctx, guint32 offset, gboolean allow_empty)
974 return is_valid_string_full_with_image (ctx->image, offset, allow_empty);
977 static gboolean
978 is_valid_string (VerifyContext *ctx, guint32 offset)
980 return is_valid_string_full (ctx, offset, TRUE);
983 static gboolean
984 is_valid_non_empty_string (VerifyContext *ctx, guint32 offset)
986 return is_valid_string_full (ctx, offset, FALSE);
989 static gboolean
990 is_valid_guid (VerifyContext *ctx, guint32 offset)
992 OffsetAndSize guids = get_metadata_stream (ctx, &ctx->image->heap_guid);
993 return guids.size >= 8 && guids.size - 8 >= offset;
996 static guint32
997 get_coded_index_token (int token_kind, guint32 coded_token)
999 guint32 bits = coded_index_desc [token_kind];
1000 return coded_token >> bits;
1003 static guint32
1004 get_coded_index_table (int kind, guint32 coded_token)
1006 guint32 idx, bits = coded_index_desc [kind];
1007 kind += 2;
1008 idx = coded_token & ((1 << bits) - 1);
1009 return coded_index_desc [kind + idx];
1012 static guint32
1013 make_coded_token (int kind, guint32 table, guint32 table_idx)
1015 guint32 bits = coded_index_desc [kind++];
1016 guint32 tables = coded_index_desc [kind++];
1017 guint32 i;
1018 for (i = 0; i < tables; ++i) {
1019 if (coded_index_desc [kind++] == table)
1020 return ((table_idx + 1) << bits) | i;
1022 g_assert_not_reached ();
1023 return -1;
1026 static gboolean
1027 is_valid_coded_index_with_image (MonoImage *image, int token_kind, guint32 coded_token)
1029 guint32 bits = coded_index_desc [token_kind++];
1030 guint32 table_count = coded_index_desc [token_kind++];
1031 guint32 table = coded_token & ((1 << bits) - 1);
1032 guint32 token = coded_token >> bits;
1034 if (table >= table_count)
1035 return FALSE;
1037 /*token_kind points to the first table idx*/
1038 table = coded_index_desc [token_kind + table];
1040 if (table == INVALID_TABLE)
1041 return FALSE;
1042 return token <= image->tables [table].rows;
1045 static gboolean
1046 is_valid_coded_index (VerifyContext *ctx, int token_kind, guint32 coded_token)
1048 return is_valid_coded_index_with_image (ctx->image, token_kind, coded_token);
1051 typedef struct {
1052 guint32 token;
1053 guint32 col_size;
1054 guint32 col_offset;
1055 MonoTableInfo *table;
1056 } RowLocator;
1058 static int
1059 token_locator (const void *a, const void *b)
1061 RowLocator *loc = (RowLocator *)a;
1062 unsigned const char *row = (unsigned const char *)b;
1063 guint32 token = loc->col_size == 2 ? read16 (row + loc->col_offset) : read32 (row + loc->col_offset);
1065 VERIFIER_DEBUG ( printf ("\tfound token %x at idx %d\n", token, ((const char*)row - loc->table->base) / loc->table->row_size) );
1066 return (int)loc->token - (int)token;
1069 static int
1070 search_sorted_table (VerifyContext *ctx, int table, int column, guint32 coded_token)
1072 MonoTableInfo *tinfo = &ctx->image->tables [table];
1073 RowLocator locator;
1074 const char *res, *base;
1075 locator.token = coded_token;
1076 locator.col_offset = get_col_offset (ctx, table, column);
1077 locator.col_size = get_col_size (ctx, table, column);
1078 locator.table = tinfo;
1080 base = tinfo->base;
1082 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) );
1083 res = (const char *)mono_binary_search (&locator, base, tinfo->rows, tinfo->row_size, token_locator);
1084 if (!res)
1085 return -1;
1087 return (res - base) / tinfo->row_size;
1090 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1091 static const char*
1092 get_string_ptr (VerifyContext *ctx, guint offset)
1094 return ctx->image->heap_strings.data + offset;
1097 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1098 static int
1099 string_cmp (VerifyContext *ctx, const char *str, guint offset)
1101 if (offset == 0)
1102 return strcmp (str, "");
1104 return strcmp (str, get_string_ptr (ctx, offset));
1107 static gboolean
1108 mono_verifier_is_corlib (MonoImage *image)
1110 gboolean trusted_location = !mono_security_core_clr_enabled () ?
1111 TRUE : mono_security_core_clr_is_platform_image (image);
1113 return trusted_location && image->module_name && !strcmp ("mscorlib.dll", image->module_name);
1116 static gboolean
1117 typedef_is_system_object (VerifyContext *ctx, guint32 *data)
1119 return mono_verifier_is_corlib (ctx->image) && !string_cmp (ctx, "System", data [MONO_TYPEDEF_NAMESPACE]) && !string_cmp (ctx, "Object", data [MONO_TYPEDEF_NAME]);
1122 static gboolean
1123 decode_value (const char *_ptr, unsigned available, unsigned *value, unsigned *size)
1125 unsigned char b;
1126 const unsigned char *ptr = (const unsigned char *)_ptr;
1128 if (!available)
1129 return FALSE;
1131 b = *ptr;
1132 *value = *size = 0;
1134 if ((b & 0x80) == 0) {
1135 *size = 1;
1136 *value = b;
1137 } else if ((b & 0x40) == 0) {
1138 if (available < 2)
1139 return FALSE;
1140 *size = 2;
1141 *value = ((b & 0x3f) << 8 | ptr [1]);
1142 } else {
1143 if (available < 4)
1144 return FALSE;
1145 *size = 4;
1146 *value = ((b & 0x1f) << 24) |
1147 (ptr [1] << 16) |
1148 (ptr [2] << 8) |
1149 ptr [3];
1152 return TRUE;
1155 static gboolean
1156 decode_signature_header (VerifyContext *ctx, guint32 offset, guint32 *size, const char **first_byte)
1158 MonoStreamHeader blob = ctx->image->heap_blob;
1159 guint32 value, enc_size;
1161 if (offset >= blob.size)
1162 return FALSE;
1164 if (!decode_value (blob.data + offset, blob.size - offset, &value, &enc_size))
1165 return FALSE;
1167 if (CHECK_ADD4_OVERFLOW_UN (offset, enc_size))
1168 return FALSE;
1170 offset += enc_size;
1172 if (ADD_IS_GREATER_OR_OVF (offset, value, blob.size))
1173 return FALSE;
1175 *size = value;
1176 *first_byte = blob.data + offset;
1177 return TRUE;
1180 static gboolean
1181 safe_read (const char **_ptr, const char *limit, unsigned *dest, int size)
1183 const char *ptr = *_ptr;
1184 if (ptr + size > limit)
1185 return FALSE;
1186 switch (size) {
1187 case 1:
1188 *dest = *((guint8*)ptr);
1189 ++ptr;
1190 break;
1191 case 2:
1192 *dest = read16 (ptr);
1193 ptr += 2;
1194 break;
1195 case 4:
1196 *dest = read32 (ptr);
1197 ptr += 4;
1198 break;
1200 *_ptr = ptr;
1201 return TRUE;
1204 static gboolean
1205 safe_read_compressed_int (const char **_ptr, const char *limit, unsigned *dest)
1207 unsigned size = 0;
1208 const char *ptr = *_ptr;
1209 gboolean res = decode_value (ptr, limit - ptr, dest, &size);
1210 *_ptr = ptr + size;
1211 return res;
1214 #define safe_read8(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 1)
1215 #define safe_read_cint(VAR, PTR, LIMIT) safe_read_compressed_int (&PTR, LIMIT, &VAR)
1216 #define safe_read16(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 2)
1217 #define safe_read32(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 4)
1219 static gboolean
1220 parse_type (VerifyContext *ctx, const char **_ptr, const char *end);
1222 static gboolean
1223 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged);
1225 static gboolean
1226 parse_custom_mods (VerifyContext *ctx, const char **_ptr, const char *end)
1228 const char *ptr = *_ptr;
1229 unsigned type = 0;
1230 unsigned token = 0;
1232 while (TRUE) {
1233 if (!safe_read8 (type, ptr, end))
1234 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the type"));
1236 if (type != MONO_TYPE_CMOD_REQD && type != MONO_TYPE_CMOD_OPT) {
1237 --ptr;
1238 break;
1241 if (!safe_read_cint (token, ptr, end))
1242 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the token"));
1244 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token) || !get_coded_index_token (TYPEDEF_OR_REF_DESC, token))
1245 FAIL (ctx, g_strdup_printf ("CustomMod: invalid TypeDefOrRef token %x", token));
1248 *_ptr = ptr;
1249 return TRUE;
1252 static gboolean
1253 parse_array_shape (VerifyContext *ctx, const char **_ptr, const char *end)
1255 const char *ptr = *_ptr;
1256 unsigned val = 0;
1257 unsigned size, num, i;
1259 if (!safe_read8 (val, ptr, end))
1260 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for Rank"));
1262 if (val == 0)
1263 FAIL (ctx, g_strdup ("ArrayShape: Invalid shape with zero Rank"));
1265 if (!safe_read_cint (size, ptr, end))
1266 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumSizes"));
1268 for (i = 0; i < size; ++i) {
1269 if (!safe_read_cint (num, ptr, end))
1270 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for Size of rank %d", i + 1));
1273 if (!safe_read_cint (size, ptr, end))
1274 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumLoBounds"));
1276 for (i = 0; i < size; ++i) {
1277 if (!safe_read_cint (num, ptr, end))
1278 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for LoBound of rank %d", i + 1));
1281 *_ptr = ptr;
1282 return TRUE;
1285 static gboolean
1286 parse_generic_inst (VerifyContext *ctx, const char **_ptr, const char *end)
1288 const char *ptr = *_ptr;
1289 unsigned type;
1290 unsigned count, token, i;
1292 if (!safe_read8 (type, ptr, end))
1293 FAIL (ctx, g_strdup ("GenericInst: Not enough room for kind"));
1295 if (type != MONO_TYPE_CLASS && type != MONO_TYPE_VALUETYPE)
1296 FAIL (ctx, g_strdup_printf ("GenericInst: Invalid GenericInst kind %x\n", type));
1298 if (!safe_read_cint (token, ptr, end))
1299 FAIL (ctx, g_strdup ("GenericInst: Not enough room for type token"));
1301 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token) || !get_coded_index_token (TYPEDEF_OR_REF_DESC, token))
1302 FAIL (ctx, g_strdup_printf ("GenericInst: invalid TypeDefOrRef token %x", token));
1304 if (ctx->token) {
1305 if (mono_metadata_token_index (ctx->token) == get_coded_index_token (TYPEDEF_OR_REF_DESC, token) &&
1306 mono_metadata_token_table (ctx->token) == get_coded_index_table (TYPEDEF_OR_REF_DESC, token))
1307 FAIL (ctx, g_strdup_printf ("Type: Recurside generic instance specification (%x). A type signature can't reference itself", ctx->token));
1310 if (!safe_read_cint (count, ptr, end))
1311 FAIL (ctx, g_strdup ("GenericInst: Not enough room for argument count"));
1313 if (count == 0)
1314 FAIL (ctx, g_strdup ("GenericInst: Zero arguments generic instance"));
1316 for (i = 0; i < count; ++i) {
1317 if (!parse_custom_mods (ctx, &ptr, end))
1318 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1320 if (!parse_type (ctx, &ptr, end))
1321 FAIL (ctx, g_strdup_printf ("GenericInst: invalid generic argument %d", i + 1));
1323 *_ptr = ptr;
1324 return TRUE;
1327 static gboolean
1328 parse_type (VerifyContext *ctx, const char **_ptr, const char *end)
1330 const char *ptr = *_ptr;
1331 unsigned type;
1332 unsigned token = 0;
1334 if (!safe_read8 (type, ptr, end))
1335 FAIL (ctx, g_strdup ("Type: Not enough room for the type"));
1337 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_PTR) ||
1338 (type >= MONO_TYPE_VALUETYPE && type <= MONO_TYPE_GENERICINST) ||
1339 (type >= MONO_TYPE_I && type <= MONO_TYPE_U) ||
1340 (type >= MONO_TYPE_FNPTR && type <= MONO_TYPE_MVAR)))
1341 FAIL (ctx, g_strdup_printf ("Type: Invalid type kind %x\n", type));
1343 switch (type) {
1344 case MONO_TYPE_PTR:
1345 if (!parse_custom_mods (ctx, &ptr, end))
1346 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1348 if (!safe_read8 (type, ptr, end))
1349 FAIL (ctx, g_strdup ("Type: Not enough room to parse the pointer type"));
1351 if (type != MONO_TYPE_VOID) {
1352 --ptr;
1353 if (!parse_type (ctx, &ptr, end))
1354 FAIL (ctx, g_strdup ("Type: Could not parse pointer type"));
1356 break;
1358 case MONO_TYPE_VALUETYPE:
1359 case MONO_TYPE_CLASS:
1360 if (!safe_read_cint (token, ptr, end))
1361 FAIL (ctx, g_strdup ("Type: Not enough room for the type token"));
1363 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token) || !get_coded_index_token (TYPEDEF_OR_REF_DESC, token))
1364 FAIL (ctx, g_strdup_printf ("Type: invalid TypeDefOrRef token %x", token));
1366 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, token))
1367 FAIL (ctx, g_strdup_printf ("Type: zero TypeDefOrRef token %x", token));
1368 if (ctx->token) {
1369 if (mono_metadata_token_index (ctx->token) == get_coded_index_token (TYPEDEF_OR_REF_DESC, token) &&
1370 mono_metadata_token_table (ctx->token) == get_coded_index_table (TYPEDEF_OR_REF_DESC, token))
1371 FAIL (ctx, g_strdup_printf ("Type: Recursive type specification (%x). A type signature can't reference itself", ctx->token));
1373 break;
1375 case MONO_TYPE_VAR:
1376 case MONO_TYPE_MVAR:
1377 if (!safe_read_cint (token, ptr, end))
1378 FAIL (ctx, g_strdup ("Type: Not enough room for to decode generic argument number"));
1379 break;
1381 case MONO_TYPE_ARRAY:
1382 if (!parse_type (ctx, &ptr, end))
1383 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1384 if (!parse_array_shape (ctx, &ptr, end))
1385 FAIL (ctx, g_strdup ("Type: Could not parse array shape"));
1386 break;
1388 case MONO_TYPE_GENERICINST:
1389 if (!parse_generic_inst (ctx, &ptr, end))
1390 FAIL (ctx, g_strdup ("Type: Could not parse generic inst"));
1391 break;
1393 case MONO_TYPE_FNPTR:
1394 if (!parse_method_signature (ctx, &ptr, end, TRUE, TRUE))
1395 FAIL (ctx, g_strdup ("Type: Could not parse method pointer signature"));
1396 break;
1398 case MONO_TYPE_SZARRAY:
1399 if (!parse_custom_mods (ctx, &ptr, end))
1400 FAIL (ctx, g_strdup ("Type: Failed to parse array element custom attr"));
1401 if (!parse_type (ctx, &ptr, end))
1402 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1403 break;
1405 *_ptr = ptr;
1406 return TRUE;
1409 static gboolean
1410 parse_return_type (VerifyContext *ctx, const char **_ptr, const char *end)
1412 const char *ptr;
1413 unsigned type = 0;
1415 if (!parse_custom_mods (ctx, _ptr, end))
1416 return FALSE;
1418 ptr = *_ptr;
1419 if (!safe_read8 (type, ptr, end))
1420 FAIL (ctx, g_strdup ("ReturnType: Not enough room for the type"));
1422 if (type == MONO_TYPE_VOID || type == MONO_TYPE_TYPEDBYREF) {
1423 *_ptr = ptr;
1424 return TRUE;
1427 //it's a byref, update the cursor ptr
1428 if (type == MONO_TYPE_BYREF)
1429 *_ptr = ptr;
1431 return parse_type (ctx, _ptr, end);
1434 static gboolean
1435 parse_param (VerifyContext *ctx, const char **_ptr, const char *end)
1437 const char *ptr;
1438 unsigned type = 0;
1440 if (!parse_custom_mods (ctx, _ptr, end))
1441 return FALSE;
1443 ptr = *_ptr;
1444 if (!safe_read8 (type, ptr, end))
1445 FAIL (ctx, g_strdup ("Param: Not enough room for the type"));
1447 if (type == MONO_TYPE_TYPEDBYREF) {
1448 *_ptr = ptr;
1449 return TRUE;
1452 //it's a byref, update the cursor ptr
1453 if (type == MONO_TYPE_BYREF) {
1454 *_ptr = ptr;
1455 if (!parse_custom_mods (ctx, _ptr, end))
1456 return FALSE;
1459 return parse_type (ctx, _ptr, end);
1462 static gboolean
1463 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged)
1465 unsigned cconv = 0;
1466 unsigned param_count = 0, gparam_count = 0, type = 0, i;
1467 const char *ptr = *_ptr;
1468 gboolean saw_sentinel = FALSE;
1470 if (!safe_read8 (cconv, ptr, end))
1471 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the call conv"));
1473 if (cconv & 0x80)
1474 FAIL (ctx, g_strdup ("MethodSig: CallConv has 0x80 set"));
1476 if (allow_unmanaged) {
1477 if ((cconv & 0x0F) > MONO_CALL_VARARG)
1478 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not valid, it's %x", cconv & 0x0F));
1479 } else if ((cconv & 0x0F) != MONO_CALL_DEFAULT && (cconv & 0x0F) != MONO_CALL_VARARG)
1480 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not Default or Vararg, it's %x", cconv & 0x0F));
1482 if ((cconv & 0x10) && !safe_read_cint (gparam_count, ptr, end))
1483 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the generic param count"));
1485 if ((cconv & 0x10) && gparam_count == 0)
1486 FAIL (ctx, g_strdup ("MethodSig: Signature with generics but zero arity"));
1488 if (allow_unmanaged && (cconv & 0x10))
1489 FAIL (ctx, g_strdup ("MethodSig: Standalone signature with generic params"));
1491 if (!safe_read_cint (param_count, ptr, end))
1492 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the param count"));
1494 if (!parse_return_type (ctx, &ptr, end))
1495 FAIL (ctx, g_strdup ("MethodSig: Error parsing return type"));
1497 for (i = 0; i < param_count; ++i) {
1498 if (allow_sentinel) {
1499 if (!safe_read8 (type, ptr, end))
1500 FAIL (ctx, g_strdup_printf ("MethodSig: Not enough room for param %d type", i));
1502 if (type == MONO_TYPE_SENTINEL) {
1503 if ((cconv & 0x0F) != MONO_CALL_VARARG)
1504 FAIL (ctx, g_strdup ("MethodSig: Found sentinel but signature is not vararg"));
1506 if (saw_sentinel)
1507 FAIL (ctx, g_strdup ("MethodSig: More than one sentinel type"));
1509 saw_sentinel = TRUE;
1510 } else {
1511 --ptr;
1515 if (!parse_param (ctx, &ptr, end))
1516 FAIL (ctx, g_strdup_printf ("MethodSig: Error parsing arg %d", i));
1519 *_ptr = ptr;
1520 return TRUE;
1523 static gboolean
1524 parse_property_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1526 unsigned type = 0;
1527 unsigned sig = 0;
1528 unsigned param_count = 0, i;
1529 const char *ptr = *_ptr;
1531 if (!safe_read8 (sig, ptr, end))
1532 FAIL (ctx, g_strdup ("PropertySig: Not enough room for signature"));
1534 if (sig != 0x08 && sig != 0x28)
1535 FAIL (ctx, g_strdup_printf ("PropertySig: Signature is not 0x28 or 0x08: %x", sig));
1537 if (!safe_read_cint (param_count, ptr, end))
1538 FAIL (ctx, g_strdup ("PropertySig: Not enough room for the param count"));
1540 if (!parse_custom_mods (ctx, &ptr, end))
1541 return FALSE;
1543 if (!safe_read8 (type, ptr, end))
1544 FAIL (ctx, g_strdup ("PropertySig: Not enough room for the type"));
1546 //check if it's a byref. safe_read8 did update ptr, so we rollback if it's not a byref
1547 if (type != MONO_TYPE_BYREF)
1548 --ptr;
1550 if (!parse_type (ctx, &ptr, end))
1551 FAIL (ctx, g_strdup ("PropertySig: Could not parse property type"));
1553 for (i = 0; i < param_count; ++i) {
1554 if (!parse_custom_mods (ctx, &ptr, end))
1555 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1556 if (!parse_type (ctx, &ptr, end))
1557 FAIL (ctx, g_strdup_printf ("PropertySig: Error parsing arg %d", i));
1560 *_ptr = ptr;
1561 return TRUE;
1564 static gboolean
1565 parse_field (VerifyContext *ctx, const char **_ptr, const char *end)
1567 const char *ptr = *_ptr;
1568 unsigned signature = 0;
1570 if (!safe_read8 (signature, ptr, end))
1571 FAIL (ctx, g_strdup ("Field: Not enough room for field signature"));
1573 if (signature != 0x06)
1574 FAIL (ctx, g_strdup_printf ("Field: Invalid signature 0x%x, must be 6", signature));
1576 if (!parse_custom_mods (ctx, &ptr, end))
1577 return FALSE;
1579 if (safe_read8 (signature, ptr, end)) {
1580 if (signature != MONO_TYPE_BYREF)
1581 --ptr;
1583 *_ptr = ptr;
1585 return parse_type (ctx, _ptr, end);
1588 static gboolean
1589 parse_locals_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1591 unsigned sig = 0;
1592 unsigned locals_count = 0, i;
1593 const char *ptr = *_ptr;
1595 if (!safe_read8 (sig, ptr, end))
1596 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for signature"));
1598 if (sig != 0x07)
1599 FAIL (ctx, g_strdup_printf ("LocalsSig: Signature is not 0x28 or 0x08: %x", sig));
1601 if (!safe_read_cint (locals_count, ptr, end))
1602 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for the param count"));
1604 /* LAMEIMPL: MS sometimes generates empty local signatures and its verifier is ok with.
1605 if (locals_count == 0)
1606 FAIL (ctx, g_strdup ("LocalsSig: Signature with zero locals"));
1609 for (i = 0; i < locals_count; ++i) {
1610 if (!safe_read8 (sig, ptr, end))
1611 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1613 while (sig == MONO_TYPE_CMOD_REQD || sig == MONO_TYPE_CMOD_OPT || sig == MONO_TYPE_PINNED) {
1614 if (sig != MONO_TYPE_PINNED && !parse_custom_mods (ctx, &ptr, end))
1615 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1616 if (!safe_read8 (sig, ptr, end))
1617 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1620 if (sig == MONO_TYPE_BYREF) {
1621 if (!safe_read8 (sig, ptr, end))
1622 FAIL (ctx, g_strdup_printf ("Type: Not enough room for byref type for local %d", i));
1623 if (sig == MONO_TYPE_TYPEDBYREF)
1624 FAIL (ctx, g_strdup_printf ("Type: Invalid type typedref& for local %d", i));
1627 if (sig == MONO_TYPE_TYPEDBYREF)
1628 continue;
1630 --ptr;
1632 if (!parse_type (ctx, &ptr, end))
1633 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1636 *_ptr = ptr;
1637 return TRUE;
1640 static gboolean
1641 is_valid_field_signature (VerifyContext *ctx, guint32 offset)
1643 guint32 size = 0;
1644 unsigned signature = 0;
1645 const char *ptr = NULL, *end;
1647 if (!decode_signature_header (ctx, offset, &size, &ptr))
1648 FAIL (ctx, g_strdup ("FieldSig: Could not decode signature header"));
1649 end = ptr + size;
1651 if (!safe_read8 (signature, ptr, end))
1652 FAIL (ctx, g_strdup ("FieldSig: Not enough room for the signature"));
1654 if (signature != 6)
1655 FAIL (ctx, g_strdup_printf ("FieldSig: Invalid signature %x", signature));
1656 --ptr;
1658 return parse_field (ctx, &ptr, end);
1661 static gboolean
1662 is_valid_method_signature (VerifyContext *ctx, guint32 offset)
1664 guint32 size = 0;
1665 const char *ptr = NULL, *end;
1667 if (!decode_signature_header (ctx, offset, &size, &ptr))
1668 FAIL (ctx, g_strdup ("MethodSig: Could not decode signature header"));
1669 end = ptr + size;
1671 return parse_method_signature (ctx, &ptr, end, FALSE, FALSE);
1674 static gboolean
1675 is_valid_memberref_method_signature (VerifyContext *ctx, guint32 offset)
1677 guint32 size = 0;
1678 const char *ptr = NULL, *end;
1680 if (!decode_signature_header (ctx, offset, &size, &ptr))
1681 FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
1682 end = ptr + size;
1684 return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1688 static gboolean
1689 is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
1691 guint32 size = 0;
1692 unsigned signature = 0;
1693 const char *ptr = NULL, *end;
1695 if (!decode_signature_header (ctx, offset, &size, &ptr))
1696 FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
1697 end = ptr + size;
1699 if (!safe_read8 (signature, ptr, end))
1700 FAIL (ctx, g_strdup ("MemberRefSig: Not enough room for the call conv"));
1701 --ptr;
1703 if (signature == 0x06)
1704 return parse_field (ctx, &ptr, end);
1706 return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1709 static gboolean
1710 is_valid_cattr_blob (VerifyContext *ctx, guint32 offset)
1712 guint32 size = 0;
1713 unsigned prolog = 0;
1714 const char *ptr = NULL, *end;
1716 if (!offset)
1717 return TRUE;
1719 if (!decode_signature_header (ctx, offset, &size, &ptr))
1720 FAIL (ctx, g_strdup ("CustomAttribute: Could not decode signature header"));
1721 end = ptr + size;
1723 if (!safe_read16 (prolog, ptr, end))
1724 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1726 if (prolog != 1)
1727 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1729 return TRUE;
1732 static gboolean
1733 is_valid_cattr_type (MonoType *type)
1735 MonoClass *klass;
1737 if (type->type == MONO_TYPE_OBJECT || (type->type >= MONO_TYPE_BOOLEAN && type->type <= MONO_TYPE_STRING))
1738 return TRUE;
1740 if (type->type == MONO_TYPE_VALUETYPE) {
1741 klass = mono_class_from_mono_type_internal (type);
1742 return klass && m_class_is_enumtype (klass);
1745 if (type->type == MONO_TYPE_CLASS)
1746 return mono_class_from_mono_type_internal (type) == mono_defaults.systemtype_class;
1748 return FALSE;
1751 static gboolean
1752 is_valid_ser_string_full (VerifyContext *ctx, const char **str_start, guint32 *str_len, const char **_ptr, const char *end)
1754 guint32 size = 0;
1755 const char *ptr = *_ptr;
1757 *str_start = NULL;
1758 *str_len = 0;
1760 if (ptr >= end)
1761 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string size"));
1763 MONO_DISABLE_WARNING (4310) // cast truncates constant value
1764 /*NULL string*/
1765 if (*ptr == (char)0xFF) {
1766 *_ptr = ptr + 1;
1767 return TRUE;
1769 MONO_RESTORE_WARNING
1771 if (!safe_read_cint (size, ptr, end))
1772 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string size"));
1774 if (ADDP_IS_GREATER_OR_OVF (ptr, size, end))
1775 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string"));
1777 *str_start = ptr;
1778 *str_len = size;
1780 *_ptr = ptr + size;
1781 return TRUE;
1784 static gboolean
1785 is_valid_ser_string (VerifyContext *ctx, const char **_ptr, const char *end)
1787 const char *dummy_str;
1788 guint32 dummy_int;
1789 return is_valid_ser_string_full (ctx, &dummy_str, &dummy_int, _ptr, end);
1792 static MonoClass*
1793 get_enum_by_encoded_name (VerifyContext *ctx, const char **_ptr, const char *end)
1795 ERROR_DECL (error);
1796 MonoType *type;
1797 MonoClass *klass;
1798 const char *str_start = NULL;
1799 const char *ptr = *_ptr;
1800 char *enum_name;
1801 guint32 str_len = 0;
1803 if (!is_valid_ser_string_full (ctx, &str_start, &str_len, &ptr, end))
1804 return NULL;
1806 /*NULL or empty string*/
1807 if (str_start == NULL || str_len == 0) {
1808 ADD_ERROR_NO_RETURN (ctx, g_strdup ("CustomAttribute: Null or empty enum name"));
1809 return NULL;
1812 enum_name = (char *)g_memdup (str_start, str_len + 1);
1813 enum_name [str_len] = 0;
1814 type = mono_reflection_type_from_name_checked (enum_name, ctx->image, error);
1815 if (!type || !is_ok (error)) {
1816 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute: Invalid enum class %s, due to %s", enum_name, mono_error_get_message (error)));
1817 g_free (enum_name);
1818 mono_error_cleanup (error);
1819 return NULL;
1821 g_free (enum_name);
1823 klass = mono_class_from_mono_type_internal (type);
1824 if (!klass || !m_class_is_enumtype (klass)) {
1825 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute:Class %s::%s is not an enum", m_class_get_name_space (klass), m_class_get_name (klass)));
1826 return NULL;
1829 *_ptr = ptr;
1830 return klass;
1833 static gboolean
1834 is_valid_fixed_param (VerifyContext *ctx, MonoType *mono_type, const char **_ptr, const char *end)
1836 MonoClass *klass;
1837 const char *ptr = *_ptr;
1838 int elem_size = 0;
1839 guint32 element_count, i;
1840 int type;
1842 klass = mono_type->data.klass;
1843 type = mono_type->type;
1845 handle_enum:
1846 switch (type) {
1847 case MONO_TYPE_BOOLEAN:
1848 case MONO_TYPE_I1:
1849 case MONO_TYPE_U1:
1850 elem_size = 1;
1851 break;
1852 case MONO_TYPE_I2:
1853 case MONO_TYPE_U2:
1854 case MONO_TYPE_CHAR:
1855 elem_size = 2;
1856 break;
1857 case MONO_TYPE_I4:
1858 case MONO_TYPE_U4:
1859 case MONO_TYPE_R4:
1860 elem_size = 4;
1861 break;
1862 case MONO_TYPE_I8:
1863 case MONO_TYPE_U8:
1864 case MONO_TYPE_R8:
1865 elem_size = 8;
1866 break;
1868 case MONO_TYPE_STRING:
1869 *_ptr = ptr;
1870 return is_valid_ser_string (ctx, _ptr, end);
1872 case MONO_TYPE_OBJECT: {
1873 unsigned sub_type = 0;
1874 if (!safe_read8 (sub_type, ptr, end))
1875 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array type"));
1877 if (sub_type >= MONO_TYPE_BOOLEAN && sub_type <= MONO_TYPE_STRING) {
1878 type = sub_type;
1879 goto handle_enum;
1881 if (sub_type == MONO_TYPE_ENUM) {
1882 klass = get_enum_by_encoded_name (ctx, &ptr, end);
1883 if (!klass)
1884 return FALSE;
1886 klass = m_class_get_element_class (klass);
1887 type = m_class_get_byval_arg (klass)->type;
1888 goto handle_enum;
1890 if (sub_type == 0x50) { /*Type*/
1891 *_ptr = ptr;
1892 return is_valid_ser_string (ctx, _ptr, end);
1894 if (sub_type == MONO_TYPE_SZARRAY) {
1895 MonoType simple_type = {{0}};
1896 unsigned etype = 0;
1897 if (!safe_read8 (etype, ptr, end))
1898 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array element type"));
1900 if (etype == MONO_TYPE_ENUM) {
1901 klass = get_enum_by_encoded_name (ctx, &ptr, end);
1902 if (!klass)
1903 return FALSE;
1904 } else if (etype == 0x50 || etype == MONO_TYPE_CLASS) {
1905 klass = mono_defaults.systemtype_class;
1906 } else if ((etype >= MONO_TYPE_BOOLEAN && etype <= MONO_TYPE_STRING) || etype == 0x51) {
1907 simple_type.type = etype == 0x51 ? MONO_TYPE_OBJECT : (MonoTypeEnum)etype;
1908 klass = mono_class_from_mono_type_internal (&simple_type);
1909 } else
1910 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype));
1912 type = MONO_TYPE_SZARRAY;
1913 goto handle_enum;
1915 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid boxed object type %x", sub_type));
1918 case MONO_TYPE_CLASS:
1919 if (klass && m_class_is_enumtype (klass)) {
1920 klass = m_class_get_element_class (klass);
1921 type = m_class_get_byval_arg (klass)->type;
1922 goto handle_enum;
1925 if (klass != mono_defaults.systemtype_class)
1926 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid class parameter type %s:%s ",m_class_get_name_space (klass), m_class_get_name (klass)));
1927 *_ptr = ptr;
1928 return is_valid_ser_string (ctx, _ptr, end);
1930 case MONO_TYPE_VALUETYPE:
1931 if (!klass || !m_class_is_enumtype (klass))
1932 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid valuetype parameter expected enum %s:%s ",m_class_get_name_space (klass), m_class_get_name (klass)));
1934 klass = m_class_get_element_class (klass);
1935 type = m_class_get_byval_arg (klass)->type;
1936 goto handle_enum;
1938 case MONO_TYPE_SZARRAY:
1939 mono_type = m_class_get_byval_arg (klass);
1940 if (!is_valid_cattr_type (mono_type))
1941 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %s:%s ",m_class_get_name_space (klass), m_class_get_name (klass)));
1942 if (!safe_read32 (element_count, ptr, end))
1943 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid class parameter type %s:%s ",m_class_get_name_space (klass), m_class_get_name (klass)));
1944 if (element_count == 0xFFFFFFFFu) {
1945 *_ptr = ptr;
1946 return TRUE;
1948 for (i = 0; i < element_count; ++i) {
1949 if (!is_valid_fixed_param (ctx, mono_type, &ptr, end))
1950 return FALSE;
1952 *_ptr = ptr;
1953 return TRUE;
1954 default:
1955 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid parameter type %x ", type));
1958 if (ADDP_IS_GREATER_OR_OVF (ptr, elem_size, end))
1959 FAIL (ctx, g_strdup ("CustomAttribute: Not enough space for element"));
1960 *_ptr = ptr + elem_size;
1961 return TRUE;
1964 static gboolean
1965 is_valid_cattr_content (VerifyContext *ctx, MonoMethod *ctor, const char *ptr, guint32 size)
1967 ERROR_DECL (error);
1968 unsigned prolog = 0;
1969 const char *end;
1970 MonoMethodSignature *sig;
1971 int args, i;
1972 unsigned num_named;
1974 if (!ctor)
1975 FAIL (ctx, g_strdup ("CustomAttribute: Invalid constructor"));
1977 sig = mono_method_signature_checked (ctor, error);
1978 if (!mono_error_ok (error)) {
1979 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute: Invalid constructor signature %s", mono_error_get_message (error)));
1980 mono_error_cleanup (error);
1981 return FALSE;
1984 if (sig->sentinelpos != -1 || sig->call_convention == MONO_CALL_VARARG)
1985 FAIL (ctx, g_strdup ("CustomAttribute: Constructor cannot have VARAG signature"));
1987 end = ptr + size;
1989 if (!safe_read16 (prolog, ptr, end))
1990 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1992 if (prolog != 1)
1993 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1995 args = sig->param_count;
1996 for (i = 0; i < args; ++i) {
1997 MonoType *arg_type = sig->params [i];
1998 if (!is_valid_fixed_param (ctx, arg_type, &ptr, end))
1999 return FALSE;
2002 if (!safe_read16 (num_named, ptr, end))
2003 FAIL (ctx, g_strdup ("CustomAttribute: Not enough space for num_named field"));
2005 for (i = 0; i < num_named; ++i) {
2006 MonoType *type, simple_type = {{0}};
2007 unsigned kind;
2009 if (!safe_read8 (kind, ptr, end))
2010 FAIL (ctx, g_strdup_printf ("CustomAttribute: Not enough space for named parameter %d kind", i));
2011 if (kind != 0x53 && kind != 0x54)
2012 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid named parameter %d kind %x", i, kind));
2013 if (!safe_read8 (kind, ptr, end))
2014 FAIL (ctx, g_strdup_printf ("CustomAttribute: Not enough space for named parameter %d type", i));
2016 if (kind >= MONO_TYPE_BOOLEAN && kind <= MONO_TYPE_STRING) {
2017 simple_type.type = (MonoTypeEnum)kind;
2018 type = &simple_type;
2019 } else if (kind == MONO_TYPE_ENUM) {
2020 MonoClass *klass = get_enum_by_encoded_name (ctx, &ptr, end);
2021 if (!klass)
2022 return FALSE;
2023 type = m_class_get_byval_arg (klass);
2024 } else if (kind == 0x50) {
2025 type = m_class_get_byval_arg (mono_defaults.systemtype_class);
2026 } else if (kind == 0x51) {
2027 type = mono_get_object_type ();
2028 } else if (kind == MONO_TYPE_SZARRAY) {
2029 MonoClass *klass;
2030 unsigned etype = 0;
2031 if (!safe_read8 (etype, ptr, end))
2032 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array element type"));
2034 if (etype == MONO_TYPE_ENUM) {
2035 klass = get_enum_by_encoded_name (ctx, &ptr, end);
2036 if (!klass)
2037 return FALSE;
2038 } else if (etype == 0x50 || etype == MONO_TYPE_CLASS) {
2039 klass = mono_defaults.systemtype_class;
2040 } else if ((etype >= MONO_TYPE_BOOLEAN && etype <= MONO_TYPE_STRING) || etype == 0x51) {
2041 simple_type.type = etype == 0x51 ? MONO_TYPE_OBJECT : (MonoTypeEnum)etype;
2042 klass = mono_class_from_mono_type_internal (&simple_type);
2043 } else
2044 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype));
2046 type = m_class_get_byval_arg (mono_class_create_array (klass, 1));
2047 } else {
2048 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid named parameter type %x", kind));
2051 if (!is_valid_ser_string (ctx, &ptr, end))
2052 return FALSE;
2054 if (!is_valid_fixed_param (ctx, type, &ptr, end))
2055 return FALSE;
2059 return TRUE;
2062 static gboolean
2063 is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
2065 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2066 //TODO do proper verification
2067 return blob.size >= 1 && blob.size - 1 >= offset;
2070 static gboolean
2071 is_valid_permission_set (VerifyContext *ctx, guint32 offset)
2073 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2074 //TODO do proper verification
2075 return blob.size >= 1 && blob.size - 1 >= offset;
2078 static gboolean
2079 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
2081 guint32 size = 0;
2082 unsigned signature = 0;
2083 const char *ptr = NULL, *end;
2085 if (!decode_signature_header (ctx, offset, &size, &ptr))
2086 FAIL (ctx, g_strdup ("StandAloneSig: Could not decode signature header"));
2087 end = ptr + size;
2089 if (!safe_read8 (signature, ptr, end))
2090 FAIL (ctx, g_strdup ("StandAloneSig: Not enough room for the call conv"));
2092 --ptr;
2093 if (signature == 0x07)
2094 return parse_locals_signature (ctx, &ptr, end);
2096 /*F# and managed C++ produce standalonesig for fields even thou the spec doesn't mention it.*/
2097 if (signature == 0x06)
2098 return parse_field (ctx, &ptr, end);
2100 return parse_method_signature (ctx, &ptr, end, TRUE, TRUE);
2103 static gboolean
2104 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
2106 guint32 size = 0;
2107 const char *ptr = NULL, *end;
2109 if (!decode_signature_header (ctx, offset, &size, &ptr))
2110 FAIL (ctx, g_strdup ("PropertySig: Could not decode signature header"));
2111 end = ptr + size;
2113 return parse_property_signature (ctx, &ptr, end);
2116 static gboolean
2117 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
2119 guint32 size = 0;
2120 const char *ptr = NULL, *end;
2121 unsigned type = 0;
2123 if (!decode_signature_header (ctx, offset, &size, &ptr))
2124 FAIL (ctx, g_strdup ("TypeSpec: Could not decode signature header"));
2125 end = ptr + size;
2127 if (!parse_custom_mods (ctx, &ptr, end))
2128 return FALSE;
2130 if (!safe_read8 (type, ptr, end))
2131 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for type"));
2133 if (type == MONO_TYPE_BYREF) {
2134 if (!safe_read8 (type, ptr, end))
2135 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for byref type"));
2136 if (type == MONO_TYPE_TYPEDBYREF)
2137 FAIL (ctx, g_strdup ("TypeSpec: Invalid type typedref&"));
2140 if (type == MONO_TYPE_TYPEDBYREF)
2141 return TRUE;
2143 --ptr;
2144 return parse_type (ctx, &ptr, end);
2147 static gboolean
2148 is_valid_methodspec_blob (VerifyContext *ctx, guint32 offset)
2150 guint32 size = 0;
2151 const char *ptr = NULL, *end;
2152 unsigned type = 0;
2153 unsigned count = 0, i;
2155 if (!decode_signature_header (ctx, offset, &size, &ptr))
2156 FAIL (ctx, g_strdup ("MethodSpec: Could not decode signature header"));
2157 end = ptr + size;
2159 if (!safe_read8 (type, ptr, end))
2160 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for call convention"));
2162 if (type != 0x0A)
2163 FAIL (ctx, g_strdup_printf ("MethodSpec: Invalid call convention 0x%x, expected 0x0A", type));
2165 if (!safe_read_cint (count, ptr, end))
2166 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for parameter count"));
2168 if (!count)
2169 FAIL (ctx, g_strdup ("MethodSpec: Zero generic argument count"));
2171 for (i = 0; i < count; ++i) {
2172 if (!parse_custom_mods (ctx, &ptr, end))
2173 return FALSE;
2174 if (!parse_type (ctx, &ptr, end))
2175 FAIL (ctx, g_strdup_printf ("MethodSpec: Could not parse parameter %d", i + 1));
2177 return TRUE;
2180 static gboolean
2181 is_valid_blob_object (VerifyContext *ctx, guint32 offset, guint32 minsize)
2183 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2184 guint32 entry_size, bytes;
2186 if (blob.size < offset)
2187 return FALSE;
2189 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
2190 return FALSE;
2192 if (entry_size < minsize)
2193 return FALSE;
2195 if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
2196 return FALSE;
2197 entry_size += bytes;
2199 return !ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size);
2202 static gboolean
2203 is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
2205 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2206 guint32 size, entry_size, bytes;
2208 if (blob.size < offset)
2209 FAIL (ctx, g_strdup ("ContantValue: invalid offset"));
2211 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
2212 FAIL (ctx, g_strdup ("ContantValue: not enough space to decode size"));
2214 if (type == MONO_TYPE_STRING) {
2215 //String is encoded as: compressed_int:len len *bytes
2216 offset += bytes;
2218 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size))
2219 FAIL (ctx, g_strdup_printf ("ContantValue: not enough space for string, required %d but got %d", entry_size * 2, blob.size - offset));
2221 return TRUE;
2224 switch (type) {
2225 case MONO_TYPE_BOOLEAN:
2226 case MONO_TYPE_I1:
2227 case MONO_TYPE_U1:
2228 size = 1;
2229 break;
2230 case MONO_TYPE_CHAR:
2231 case MONO_TYPE_I2:
2232 case MONO_TYPE_U2:
2233 size = 2;
2234 break;
2235 case MONO_TYPE_I4:
2236 case MONO_TYPE_U4:
2237 case MONO_TYPE_R4:
2238 case MONO_TYPE_CLASS:
2239 size = 4;
2240 break;
2242 case MONO_TYPE_I8:
2243 case MONO_TYPE_U8:
2244 case MONO_TYPE_R8:
2245 size = 8;
2246 break;
2247 default:
2248 g_assert_not_reached ();
2251 if (size != entry_size)
2252 FAIL (ctx, g_strdup_printf ("ContantValue: Expected size %d but got %d", size, entry_size));
2254 offset += bytes;
2256 if (ADD_IS_GREATER_OR_OVF (offset, size, blob.size))
2257 FAIL (ctx, g_strdup_printf ("ContantValue: Not enough room for constant, required %d but have %d", size, blob.size - offset));
2259 if (type == MONO_TYPE_CLASS && read32 (ctx->data + blob.offset + offset))
2260 FAIL (ctx, g_strdup_printf ("ContantValue: Type is class but value is not null"));
2261 return TRUE;
2264 #define FAT_HEADER_INVALID_FLAGS ~(0x3 | 0x8 | 0x10 | 0xF000)
2265 //only 0x01, 0x40 and 0x80 are allowed
2266 #define SECTION_HEADER_INVALID_FLAGS 0x3E
2268 static gboolean
2269 is_valid_method_header (VerifyContext *ctx, guint32 rva, guint32 *locals_token)
2271 unsigned local_vars_tok, code_size, offset = mono_cli_rva_image_map (ctx->image, rva);
2272 unsigned header = 0;
2273 unsigned fat_header = 0, size = 0, max_stack;
2274 const char *ptr = NULL, *end;
2276 *locals_token = 0;
2278 if (offset == INVALID_ADDRESS)
2279 FAIL (ctx, g_strdup ("MethodHeader: Invalid RVA"));
2281 ptr = ctx->data + offset;
2282 end = ctx->data + ctx->size; /*no worries if it spawns multiple sections*/
2284 if (!safe_read8 (header, ptr, end))
2285 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for header"));
2287 switch (header & 0x3) {
2288 case 0:
2289 case 1:
2290 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid header type 0x%x", header & 0x3));
2291 case 2:
2292 header >>= 2;
2293 if (ADDP_IS_GREATER_OR_OVF (ptr, header, end))
2294 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for method body. Required %d, but only %d is available", header, (int)(end - ptr)));
2295 return TRUE;
2297 //FAT HEADER
2298 --ptr;
2299 if (!safe_read16 (fat_header, ptr, end))
2300 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for fat header"));
2302 size = (fat_header >> 12) & 0xF;
2303 if (size != 3)
2304 FAIL (ctx, g_strdup ("MethodHeader: header size must be 3"));
2306 if (!safe_read16 (max_stack, ptr, end))
2307 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for max stack"));
2309 if (!safe_read32 (code_size, ptr, end))
2310 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for code size"));
2312 if (!safe_read32 (local_vars_tok, ptr, end))
2313 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for local vars tok"));
2315 if (local_vars_tok) {
2316 if (((local_vars_tok >> 24) & 0xFF) != 0x11)
2317 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature table 0x%x", ((local_vars_tok >> 24) & 0xFF)));
2318 if ((local_vars_tok & 0xFFFFFF) > ctx->image->tables [MONO_TABLE_STANDALONESIG].rows)
2319 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature points to invalid row 0x%x", local_vars_tok & 0xFFFFFF));
2320 if (!(local_vars_tok & 0xFFFFFF))
2321 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature with zero index"));
2322 *locals_token = local_vars_tok & 0xFFFFFF;
2325 if (fat_header & FAT_HEADER_INVALID_FLAGS)
2326 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid fat signature flags %x", fat_header & FAT_HEADER_INVALID_FLAGS));
2328 if (ADDP_IS_GREATER_OR_OVF (ptr, code_size, end))
2329 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for code %d", code_size));
2331 if (!(fat_header & 0x08))
2332 return TRUE;
2334 ptr += code_size;
2336 do {
2337 unsigned section_header = 0, section_size = 0;
2338 gboolean is_fat;
2340 ptr = dword_align (ptr);
2341 if (!safe_read32 (section_header, ptr, end))
2342 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for data section header"));
2344 if (section_header & SECTION_HEADER_INVALID_FLAGS)
2345 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section header flags 0x%x", section_header & SECTION_HEADER_INVALID_FLAGS));
2347 is_fat = (section_header & METHOD_HEADER_SECTION_FAT_FORMAT) != 0;
2348 section_size = (section_header >> 8) & (is_fat ? 0xFFFFFF : 0xFF);
2350 if (section_size < 4)
2351 FAIL (ctx, g_strdup_printf ("MethodHeader: Section size too small"));
2353 if (ADDP_IS_GREATER_OR_OVF (ptr, section_size - 4, end)) /*must be section_size -4 as ptr was incremented by safe_read32*/
2354 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section content %d", section_size));
2356 if (section_header & METHOD_HEADER_SECTION_EHTABLE) {
2357 guint32 i, clauses = section_size / (is_fat ? 24 : 12);
2359 LAMEIMPL: MS emits section_size without accounting for header size.
2360 Mono does as the spec says. section_size is header + section
2361 MS's peverify happily accepts both.
2363 if ((clauses * (is_fat ? 24 : 12) != section_size) && (clauses * (is_fat ? 24 : 12) + 4 != section_size))
2364 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)));
2366 /* only verify the class token is verified as the rest is done by the IL verifier*/
2367 for (i = 0; i < clauses; ++i) {
2368 unsigned flags = *(unsigned char*)ptr;
2369 unsigned class_token = 0;
2370 ptr += (is_fat ? 20 : 8);
2371 if (!safe_read32 (class_token, ptr, end))
2372 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section %d", i));
2373 if (flags == MONO_EXCEPTION_CLAUSE_NONE && class_token) {
2374 guint table = mono_metadata_token_table (class_token);
2375 if (table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPESPEC)
2376 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token table %x", i, table));
2377 if (mono_metadata_token_index (class_token) > ctx->image->tables [table].rows)
2378 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token index %x", i, mono_metadata_token_index (class_token)));
2383 if (!(section_header & METHOD_HEADER_SECTION_MORE_SECTS))
2384 break;
2385 } while (1);
2386 return TRUE;
2389 static void
2390 verify_module_table (VerifyContext *ctx)
2392 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
2393 guint32 data [MONO_MODULE_SIZE];
2395 if (table->rows != 1)
2396 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
2398 mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
2400 if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
2401 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
2403 if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
2404 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
2406 if (data [MONO_MODULE_ENC] != 0)
2407 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
2409 if (data [MONO_MODULE_ENCBASE] != 0)
2410 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
2413 static void
2414 verify_typeref_table (VerifyContext *ctx)
2416 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
2417 ERROR_DECL (error);
2418 guint32 i;
2420 for (i = 0; i < table->rows; ++i) {
2421 mono_verifier_verify_typeref_row (ctx->image, i, error);
2422 add_from_mono_error (ctx, error);
2426 /*bits 9,11,14,15,19,21,24-31 */
2427 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
2428 static void
2429 verify_typedef_table (VerifyContext *ctx)
2431 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2432 guint32 data [MONO_TYPEDEF_SIZE];
2433 guint32 fieldlist = 1, methodlist = 1, visibility;
2434 int i;
2436 if (table->rows == 0)
2437 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2439 for (i = 0; i < table->rows; ++i) {
2440 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2441 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
2442 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x rejected bits: 0x%08x", i, data [MONO_TYPEDEF_FLAGS], data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS));
2444 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
2445 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
2447 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
2448 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2450 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
2451 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2453 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) && (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
2454 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
2456 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
2457 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
2459 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
2460 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
2462 if (data [MONO_TYPEDEF_EXTENDS] && !is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
2463 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
2465 if (data [MONO_TYPEDEF_EXTENDS] && !get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
2466 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d zero coded extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
2468 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
2469 if ((visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) &&
2470 search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1) == -1)
2471 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d has nested visibility but no rows in the NestedClass table", i));
2473 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
2474 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
2476 if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2477 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
2479 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
2480 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));
2482 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
2483 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
2485 if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
2486 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
2488 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
2489 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));
2491 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
2492 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
2496 static void
2497 verify_typedef_table_full (VerifyContext *ctx)
2499 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2500 guint32 data [MONO_TYPEDEF_SIZE];
2501 int i;
2503 if (table->rows == 0)
2504 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2506 for (i = 0; i < table->rows; ++i) {
2507 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2509 if (i == 0) {
2510 /*XXX it's ok if <module> extends object, or anything at all, actually. */
2511 /*if (data [MONO_TYPEDEF_EXTENDS] != 0)
2512 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
2514 continue;
2517 if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
2518 if (data [MONO_TYPEDEF_EXTENDS])
2519 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
2520 } else {
2521 gboolean is_sys_obj = typedef_is_system_object (ctx, data);
2522 gboolean has_parent = get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]) != 0;
2524 if (is_sys_obj) {
2525 if (has_parent)
2526 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
2527 } else {
2528 if (!has_parent) {
2529 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
2536 /*bits 3,11,14 */
2537 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
2538 static void
2539 verify_field_table (VerifyContext *ctx)
2541 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2542 guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
2543 int i;
2545 module_field_list = (guint32)-1;
2546 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2547 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2548 module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
2551 for (i = 0; i < table->rows; ++i) {
2552 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2553 flags = data [MONO_FIELD_FLAGS];
2555 if (flags & INVALID_FIELD_FLAG_BITS)
2556 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
2558 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)
2559 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
2561 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
2562 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
2564 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
2565 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
2567 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
2568 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
2570 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
2571 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
2572 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
2574 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
2575 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2576 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2578 if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
2579 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2580 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
2582 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
2583 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
2584 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2586 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
2587 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
2589 if (data [MONO_FIELD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_FIELD_SIGNATURE], 1))
2590 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature blob token 0x%x", i, data [MONO_FIELD_SIGNATURE]));
2592 //TODO verify contant flag
2594 if (i + 1 < module_field_list) {
2595 guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
2596 if (!(flags & FIELD_ATTRIBUTE_STATIC))
2597 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
2598 if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
2599 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
2604 static void
2605 verify_field_table_full (VerifyContext *ctx)
2607 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2608 guint32 data [MONO_FIELD_SIZE];
2609 int i;
2611 for (i = 0; i < table->rows; ++i) {
2612 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2614 if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
2615 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
2619 /*bits 8,9,10,11,13,14,15*/
2620 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
2621 static void
2622 verify_method_table (VerifyContext *ctx)
2624 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2625 guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
2626 guint32 paramlist = 1;
2627 gboolean is_ctor, is_cctor;
2628 const char *name;
2629 int i;
2631 module_method_list = (guint32)-1;
2632 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2633 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2634 module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
2637 for (i = 0; i < table->rows; ++i) {
2638 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2639 rva = data [MONO_METHOD_RVA];
2640 implflags = data [MONO_METHOD_IMPLFLAGS];
2641 flags = data [MONO_METHOD_FLAGS];
2642 access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
2643 code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
2646 if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
2647 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
2649 if (access == 0x7)
2650 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
2652 if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
2653 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
2655 name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
2656 is_ctor = !strcmp (".ctor", name);
2657 is_cctor = !strcmp (".cctor", name);
2659 if ((is_ctor || is_cctor) &&
2660 search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
2661 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
2663 if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
2664 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
2666 if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
2667 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
2668 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
2669 if (flags & METHOD_ATTRIBUTE_FINAL)
2670 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and Final", i));
2671 if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
2672 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
2675 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
2676 ADD_WARNING (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
2678 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
2679 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
2681 //XXX no checks against cas stuff 10,11,12,13)
2683 //TODO check iface with .ctor (15,16)
2685 if (i + 1 < module_method_list) {
2686 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2687 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
2688 if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
2689 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
2690 if (access == METHOD_ATTRIBUTE_FAMILY || access == METHOD_ATTRIBUTE_FAM_AND_ASSEM || access == METHOD_ATTRIBUTE_FAM_OR_ASSEM)
2691 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public, Private or Assembly", i));
2694 //TODO check valuetype for synchronized
2696 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
2697 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
2699 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
2700 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
2701 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
2702 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2703 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but not Static", i));
2706 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
2707 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2708 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
2710 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
2711 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
2713 //TODO check signature contents
2715 if (rva) {
2716 if ((flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) || (implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
2717 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is either Abstract, InternalCall or PinvokeImpl", i));
2718 if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
2719 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
2720 } else {
2721 if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2722 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
2725 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2726 if (rva)
2727 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
2728 if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
2729 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
2731 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
2732 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
2734 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
2735 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
2737 if (data [MONO_METHOD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHOD_SIGNATURE], 1))
2738 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature blob token 0x%x", i, data [MONO_METHOD_SIGNATURE]));
2740 if (data [MONO_METHOD_PARAMLIST] == 0)
2741 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
2743 if (data [MONO_METHOD_PARAMLIST] < paramlist)
2744 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));
2746 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
2747 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
2749 paramlist = data [MONO_METHOD_PARAMLIST];
2754 static void
2755 verify_method_table_full (VerifyContext *ctx)
2757 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2758 guint32 data [MONO_METHOD_SIZE], rva, locals_token;
2759 int i;
2761 for (i = 0; i < table->rows; ++i) {
2762 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2763 rva = data [MONO_METHOD_RVA];
2765 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
2766 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
2768 if (rva && !is_valid_method_header (ctx, rva, &locals_token))
2769 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
2773 static guint32
2774 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
2776 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2777 guint32 row = *current_method;
2778 guint32 paramlist, tmp;
2781 paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
2782 while (row < table->rows) {
2783 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
2784 if (tmp > paramlist) {
2785 *current_method = row;
2786 return tmp - paramlist;
2788 ++row;
2791 /*no more methods, all params apply to the last one*/
2792 *current_method = table->rows;
2793 return (guint32)-1;
2797 #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))
2798 static void
2799 verify_param_table (VerifyContext *ctx)
2801 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
2802 guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
2803 gboolean first_param = TRUE;
2804 int i;
2806 if (ctx->image->tables [MONO_TABLE_METHOD].rows == 0) {
2807 if (table->rows > 0)
2808 ADD_ERROR (ctx, g_strdup ("Param table has rows while the method table has zero"));
2809 return;
2812 remaining_params = get_next_param_count (ctx, &current_method);
2814 for (i = 0; i < table->rows; ++i) {
2815 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
2816 flags = data [MONO_PARAM_FLAGS];
2818 if (flags & INVALID_PARAM_FLAGS_BITS)
2819 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
2821 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
2822 if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
2823 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
2824 } else {
2825 if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
2826 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
2829 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)
2830 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
2832 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
2833 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
2835 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
2836 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
2838 first_param = FALSE;
2839 sequence = data [MONO_PARAM_SEQUENCE];
2840 if (--remaining_params == 0) {
2841 remaining_params = get_next_param_count (ctx, &current_method);
2842 first_param = TRUE;
2847 static void
2848 verify_interfaceimpl_table (VerifyContext *ctx)
2850 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
2851 guint32 data [MONO_INTERFACEIMPL_SIZE];
2852 int i;
2854 for (i = 0; i < table->rows; ++i) {
2855 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
2856 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2857 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_INTERFACEIMPL_CLASS]));
2859 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2860 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
2862 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2863 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
2867 static void
2868 verify_memberref_table (VerifyContext *ctx)
2870 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2871 guint32 data [MONO_MEMBERREF_SIZE];
2872 int i;
2874 for (i = 0; i < table->rows; ++i) {
2875 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2877 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2878 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
2880 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2881 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
2883 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
2884 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
2886 if (data [MONO_MEMBERREF_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_MEMBERREF_SIGNATURE], 1))
2887 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d invalid signature blob token 0x%x", i, data [MONO_MEMBERREF_SIGNATURE]));
2892 static void
2893 verify_memberref_table_full (VerifyContext *ctx)
2895 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2896 guint32 data [MONO_MEMBERREF_SIZE];
2897 int i;
2899 for (i = 0; i < table->rows; ++i) {
2900 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2902 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
2903 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field 0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
2907 static void
2908 verify_constant_table (VerifyContext *ctx)
2910 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
2911 guint32 data [MONO_CONSTANT_SIZE], type;
2912 int i;
2914 for (i = 0; i < table->rows; ++i) {
2915 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
2916 type = data [MONO_CONSTANT_TYPE];
2918 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
2919 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
2921 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2922 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
2924 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2925 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
2927 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
2928 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
2932 static void
2933 verify_cattr_table (VerifyContext *ctx)
2935 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2936 guint32 data [MONO_CUSTOM_ATTR_SIZE];
2937 int i;
2939 for (i = 0; i < table->rows; ++i) {
2940 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2942 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
2943 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2945 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]))
2946 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Type field 0x%08x", i, data [MONO_CUSTOM_ATTR_TYPE]));
2948 if (data [MONO_CUSTOM_ATTR_VALUE] && !is_valid_blob_object (ctx, data [MONO_CUSTOM_ATTR_VALUE], 0))
2949 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d invalid value blob 0x%x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2953 static void
2954 verify_cattr_table_full (VerifyContext *ctx)
2956 ERROR_DECL (error);
2957 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2958 MonoMethod *ctor;
2959 const char *ptr;
2960 guint32 data [MONO_CUSTOM_ATTR_SIZE], mtoken, size;
2961 int i;
2963 for (i = 0; i < table->rows; ++i) {
2964 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2966 if (!is_valid_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
2967 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2969 mtoken = data [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
2970 switch (data [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
2971 case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
2972 mtoken |= MONO_TOKEN_METHOD_DEF;
2973 break;
2974 case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
2975 mtoken |= MONO_TOKEN_MEMBER_REF;
2976 break;
2977 default:
2978 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute constructor row %d Token 0x%08x", i, data [MONO_CUSTOM_ATTR_TYPE]));
2981 ctor = mono_get_method_checked (ctx->image, mtoken, NULL, NULL, error);
2983 if (!ctor) {
2984 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute content row %d Could not load ctor due to %s", i, mono_error_get_message (error)));
2985 mono_error_cleanup (error);
2988 /*This can't fail since this is checked in is_valid_cattr_blob*/
2989 g_assert (decode_signature_header (ctx, data [MONO_CUSTOM_ATTR_VALUE], &size, &ptr));
2991 if (!is_valid_cattr_content (ctx, ctor, ptr, size)) {
2992 char *ctor_name = mono_method_full_name (ctor, TRUE);
2993 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute content row %d Value field 0x%08x ctor: %s", i, data [MONO_CUSTOM_ATTR_VALUE], ctor_name));
2994 g_free (ctor_name);
2999 static void
3000 verify_field_marshal_table (VerifyContext *ctx)
3002 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
3003 guint32 data [MONO_FIELD_MARSHAL_SIZE];
3004 int i;
3006 for (i = 0; i < table->rows; ++i) {
3007 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
3009 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
3010 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
3012 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
3013 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
3015 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
3016 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
3018 if (!is_valid_blob_object (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE], 1))
3019 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d invalid NativeType blob 0x%x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
3023 static void
3024 verify_field_marshal_table_full (VerifyContext *ctx)
3026 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
3027 guint32 data [MONO_FIELD_MARSHAL_SIZE];
3028 int i;
3030 for (i = 0; i < table->rows; ++i) {
3031 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
3033 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
3034 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
3038 static void
3039 verify_decl_security_table (VerifyContext *ctx)
3041 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
3042 guint32 data [MONO_DECL_SECURITY_SIZE];
3043 int i;
3045 for (i = 0; i < table->rows; ++i) {
3046 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
3048 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
3049 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
3051 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
3052 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
3054 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
3055 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
3059 static void
3060 verify_decl_security_table_full (VerifyContext *ctx)
3062 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
3063 guint32 data [MONO_DECL_SECURITY_SIZE];
3064 int i;
3066 for (i = 0; i < table->rows; ++i) {
3067 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
3069 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
3070 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
3074 static void
3075 verify_class_layout_table (VerifyContext *ctx)
3077 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
3078 guint32 data [MONO_CLASS_LAYOUT_SIZE];
3079 int i;
3081 for (i = 0; i < table->rows; ++i) {
3082 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
3084 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3085 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
3087 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
3088 case 0:
3089 case 1:
3090 case 2:
3091 case 4:
3092 case 8:
3093 case 16:
3094 case 32:
3095 case 64:
3096 case 128:
3097 break;
3098 default:
3099 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
3104 static void
3105 verify_field_layout_table (VerifyContext *ctx)
3107 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
3108 guint32 data [MONO_FIELD_LAYOUT_SIZE];
3109 int i;
3111 for (i = 0; i < table->rows; ++i) {
3112 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
3114 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
3115 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
3119 static void
3120 verify_standalonesig_table (VerifyContext *ctx)
3122 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
3123 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
3124 int i;
3126 for (i = 0; i < table->rows; ++i) {
3127 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
3129 if (data [MONO_STAND_ALONE_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_STAND_ALONE_SIGNATURE], 1))
3130 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d invalid signature 0x%x", i, data [MONO_STAND_ALONE_SIGNATURE]));
3134 static void
3135 verify_standalonesig_table_full (VerifyContext *ctx)
3137 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
3138 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
3139 int i;
3141 for (i = 0; i < table->rows; ++i) {
3142 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
3144 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
3145 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
3149 static void
3150 verify_eventmap_table (VerifyContext *ctx)
3152 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
3153 guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
3154 int i;
3156 for (i = 0; i < table->rows; ++i) {
3157 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
3159 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3160 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
3162 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
3163 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
3165 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
3169 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
3170 static void
3171 verify_event_table (VerifyContext *ctx)
3173 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
3174 guint32 data [MONO_EVENT_SIZE];
3175 int i;
3177 for (i = 0; i < table->rows; ++i) {
3178 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
3180 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
3181 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
3183 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
3184 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
3186 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
3187 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
3191 static void
3192 verify_event_table_full (VerifyContext *ctx)
3194 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
3195 MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
3196 guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
3197 gboolean found_add, found_remove;
3198 int i, idx;
3200 for (i = 0; i < table->rows; ++i) {
3201 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
3203 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
3204 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
3205 if (idx == -1)
3206 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
3208 //first we move to the first row for this event
3209 while (idx > 0) {
3210 if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
3211 break;
3212 --idx;
3214 //now move forward looking for AddOn and RemoveOn rows
3215 found_add = found_remove = FALSE;
3216 while (idx < sema_table->rows) {
3217 mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
3218 if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
3219 break;
3220 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
3221 found_add = TRUE;
3222 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
3223 found_remove = TRUE;
3224 if (found_add && found_remove)
3225 break;
3226 ++idx;
3229 if (!found_add)
3230 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
3231 if (!found_remove)
3232 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no RemoveOn associated method", i));
3236 static void
3237 verify_propertymap_table (VerifyContext *ctx)
3239 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
3240 guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
3241 int i;
3243 for (i = 0; i < table->rows; ++i) {
3244 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
3246 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3247 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
3249 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
3250 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
3252 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
3256 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
3257 static void
3258 verify_property_table (VerifyContext *ctx)
3260 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
3261 guint32 data [MONO_PROPERTY_SIZE];
3262 int i;
3264 for (i = 0; i < table->rows; ++i) {
3265 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
3267 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
3268 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
3270 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
3271 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
3273 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
3274 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
3276 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
3277 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
3278 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
3283 static void
3284 verify_methodimpl_table (VerifyContext *ctx)
3286 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
3287 guint32 data [MONO_METHODIMPL_SIZE];
3288 int i;
3290 for (i = 0; i < table->rows; ++i) {
3291 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
3293 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3294 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
3296 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
3297 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
3299 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
3300 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
3302 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
3303 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
3305 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
3306 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
3310 static void
3311 verify_moduleref_table (VerifyContext *ctx)
3313 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
3314 guint32 data [MONO_MODULEREF_SIZE];
3315 int i;
3317 for (i = 0; i < table->rows; ++i) {
3318 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
3320 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
3321 ADD_ERROR (ctx, g_strdup_printf ("Invalid ModuleRef row %d name field %08x", i, data [MONO_MODULEREF_NAME]));
3325 static void
3326 verify_typespec_table (VerifyContext *ctx)
3328 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
3329 guint32 data [MONO_TYPESPEC_SIZE];
3330 int i;
3332 for (i = 0; i < table->rows; ++i) {
3333 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
3335 if (data [MONO_TYPESPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_TYPESPEC_SIGNATURE], 1))
3336 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
3340 static void
3341 verify_typespec_table_full (VerifyContext *ctx)
3343 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
3344 guint32 data [MONO_TYPESPEC_SIZE];
3345 int i;
3347 for (i = 0; i < table->rows; ++i) {
3348 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
3349 ctx->token = (i + 1) | MONO_TOKEN_TYPE_SPEC;
3350 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
3351 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
3353 ctx->token = 0;
3356 #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))
3357 static void
3358 verify_implmap_table (VerifyContext *ctx)
3360 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
3361 guint32 data [MONO_IMPLMAP_SIZE], cconv;
3362 int i;
3364 for (i = 0; i < table->rows; ++i) {
3365 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
3367 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
3368 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
3370 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
3371 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
3372 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
3374 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
3375 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
3377 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
3378 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
3380 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
3381 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
3383 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
3384 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
3386 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULEREF].rows)
3387 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
3391 static void
3392 verify_fieldrva_table (VerifyContext *ctx)
3394 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
3395 guint32 data [MONO_FIELD_RVA_SIZE];
3396 int i;
3398 for (i = 0; i < table->rows; ++i) {
3399 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
3401 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
3402 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
3404 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
3405 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
3409 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 14) | (1 << 15))
3410 static void
3411 verify_assembly_table (VerifyContext *ctx)
3413 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
3414 guint32 data [MONO_ASSEMBLY_SIZE], hash;
3415 int i;
3417 if (table->rows > 1)
3418 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
3420 for (i = 0; i < table->rows; ++i) {
3421 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
3423 hash = data [MONO_ASSEMBLY_HASH_ALG];
3424 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
3425 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
3427 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
3428 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
3430 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY], 1))
3431 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
3433 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
3434 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
3436 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
3437 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
3441 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~((1 << 0) | (1 << 8) | (1 << 14) | (1 << 15))
3442 static void
3443 verify_assemblyref_table (VerifyContext *ctx)
3445 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
3446 guint32 data [MONO_ASSEMBLYREF_SIZE];
3447 int i;
3449 for (i = 0; i < table->rows; ++i) {
3450 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
3452 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
3453 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
3455 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY], 1))
3456 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
3458 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
3459 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
3461 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
3462 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
3464 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE], 1))
3465 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
3469 #define INVALID_FILE_FLAGS_BITS ~(1)
3470 static void
3471 verify_file_table (VerifyContext *ctx)
3473 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
3474 guint32 data [MONO_FILE_SIZE];
3475 int i;
3477 for (i = 0; i < table->rows; ++i) {
3478 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
3480 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
3481 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
3483 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
3484 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
3486 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE], 1))
3487 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
3491 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
3492 static void
3493 verify_exportedtype_table (VerifyContext *ctx)
3495 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
3496 guint32 data [MONO_EXP_TYPE_SIZE];
3497 int i;
3499 for (i = 0; i < table->rows; ++i) {
3500 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
3502 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
3503 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
3505 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
3506 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
3508 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
3509 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
3511 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3512 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
3514 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3515 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
3517 /*nested type can't have a namespace*/
3518 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
3519 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
3523 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
3524 static void
3525 verify_manifest_resource_table (VerifyContext *ctx)
3527 MonoCLIImageInfo *iinfo = ctx->image->image_info;
3528 MonoCLIHeader *ch = &iinfo->cli_cli_header;
3529 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
3530 guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
3531 int i;
3533 resources_size = ch->ch_resources.size;
3535 for (i = 0; i < table->rows; ++i) {
3536 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
3538 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
3539 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
3541 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
3542 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
3544 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
3545 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
3547 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
3548 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
3550 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3551 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3553 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
3554 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])));
3556 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
3557 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
3559 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
3560 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
3564 static void
3565 verify_nested_class_table (VerifyContext *ctx)
3567 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3568 guint32 data [MONO_NESTED_CLASS_SIZE];
3569 int i;
3571 for (i = 0; i < table->rows; ++i) {
3572 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
3574 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3575 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
3576 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3577 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3578 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
3579 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3583 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
3584 static void
3585 verify_generic_param_table (VerifyContext *ctx)
3587 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
3588 guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
3589 int i, param_number = 0;
3591 for (i = 0; i < table->rows; ++i) {
3592 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
3594 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
3595 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
3597 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
3598 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
3600 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
3601 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
3603 token = data [MONO_GENERICPARAM_OWNER];
3605 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
3606 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
3608 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
3609 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
3611 if (token != last_token) {
3612 param_number = 0;
3613 last_token = token;
3616 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
3617 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));
3619 ++param_number;
3623 static void
3624 verify_method_spec_table (VerifyContext *ctx)
3626 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3627 guint32 data [MONO_METHODSPEC_SIZE];
3628 int i;
3630 for (i = 0; i < table->rows; ++i) {
3631 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3633 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3634 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
3636 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3637 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
3639 if (data [MONO_METHODSPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHODSPEC_SIGNATURE], 1))
3640 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid signature token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3644 static void
3645 verify_method_spec_table_full (VerifyContext *ctx)
3647 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3648 guint32 data [MONO_METHODSPEC_SIZE];
3649 int i;
3651 for (i = 0; i < table->rows; ++i) {
3652 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3654 if (!is_valid_methodspec_blob (ctx, data [MONO_METHODSPEC_SIGNATURE]))
3655 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3659 static void
3660 verify_generic_param_constraint_table (VerifyContext *ctx)
3662 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
3663 guint32 data [MONO_GENPARCONSTRAINT_SIZE];
3664 int i;
3665 guint32 last_owner = 0, last_constraint = 0;
3667 for (i = 0; i < table->rows; ++i) {
3668 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
3670 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
3671 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_GENPARCONSTRAINT_GENERICPAR]));
3673 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3674 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
3676 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3677 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
3679 if (last_owner > data [MONO_GENPARCONSTRAINT_GENERICPAR])
3680 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d is not properly sorted. Previous value of the owner column is 0x%08x current value is 0x%08x", i, last_owner, data [MONO_GENPARCONSTRAINT_GENERICPAR]));
3682 if (last_owner == data [MONO_GENPARCONSTRAINT_GENERICPAR]) {
3683 if (last_constraint == data [MONO_GENPARCONSTRAINT_CONSTRAINT])
3684 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has duplicate constraint 0x%08x", i, last_constraint));
3685 } else {
3686 last_owner = data [MONO_GENPARCONSTRAINT_GENERICPAR];
3688 last_constraint = data [MONO_GENPARCONSTRAINT_CONSTRAINT];
3693 typedef struct {
3694 const char *name;
3695 const char *name_space;
3696 guint32 resolution_scope;
3697 } TypeDefUniqueId;
3699 static guint
3700 typedef_hash (gconstpointer _key)
3702 const TypeDefUniqueId *key = (const TypeDefUniqueId *)_key;
3703 return g_str_hash (key->name) ^ g_str_hash (key->name_space) ^ key->resolution_scope; /*XXX better salt the int key*/
3706 static gboolean
3707 typedef_equals (gconstpointer _a, gconstpointer _b)
3709 const TypeDefUniqueId *a = (const TypeDefUniqueId *)_a;
3710 const TypeDefUniqueId *b = (const TypeDefUniqueId *)_b;
3711 return !strcmp (a->name, b->name) && !strcmp (a->name_space, b->name_space) && a->resolution_scope == b->resolution_scope;
3714 static void
3715 verify_typedef_table_global_constraints (VerifyContext *ctx)
3717 int i;
3718 guint32 data [MONO_TYPEDEF_SIZE];
3719 guint32 nested_data [MONO_NESTED_CLASS_SIZE];
3720 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
3721 MonoTableInfo *nested_table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3722 GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3724 for (i = 0; i < table->rows; ++i) {
3725 guint visibility;
3726 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3727 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
3729 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAME]);
3730 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAMESPACE]);
3731 type->resolution_scope = 0;
3733 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
3734 if (visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) {
3735 int res = search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1);
3736 g_assert (res >= 0);
3738 mono_metadata_decode_row (nested_table, res, nested_data, MONO_NESTED_CLASS_SIZE);
3739 type->resolution_scope = nested_data [MONO_NESTED_CLASS_ENCLOSING];
3742 if (g_hash_table_lookup (unique_types, type)) {
3743 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));
3744 g_hash_table_destroy (unique_types);
3745 g_free (type);
3746 return;
3748 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3751 g_hash_table_destroy (unique_types);
3754 static void
3755 verify_typeref_table_global_constraints (VerifyContext *ctx)
3757 int i;
3758 guint32 data [MONO_TYPEREF_SIZE];
3759 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
3760 GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3762 for (i = 0; i < table->rows; ++i) {
3763 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3764 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
3766 type->resolution_scope = data [MONO_TYPEREF_SCOPE];
3767 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAME]);
3768 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAMESPACE]);
3770 if (g_hash_table_lookup (unique_types, type)) {
3771 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));
3772 g_hash_table_destroy (unique_types);
3773 g_free (type);
3774 return;
3776 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3779 g_hash_table_destroy (unique_types);
3782 typedef struct {
3783 guint32 klass;
3784 guint32 method_declaration;
3785 } MethodImplUniqueId;
3787 static guint
3788 methodimpl_hash (gconstpointer _key)
3790 const MethodImplUniqueId *key = (const MethodImplUniqueId *)_key;
3791 return key->klass ^ key->method_declaration;
3794 static gboolean
3795 methodimpl_equals (gconstpointer _a, gconstpointer _b)
3797 const MethodImplUniqueId *a = (const MethodImplUniqueId *)_a;
3798 const MethodImplUniqueId *b = (const MethodImplUniqueId *)_b;
3799 return a->klass == b->klass && a->method_declaration == b->method_declaration;
3802 static void
3803 verify_methodimpl_table_global_constraints (VerifyContext *ctx)
3805 int i;
3806 guint32 data [MONO_METHODIMPL_SIZE];
3807 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
3808 GHashTable *unique_impls = g_hash_table_new_full (&methodimpl_hash, &methodimpl_equals, g_free, NULL);
3810 for (i = 0; i < table->rows; ++i) {
3811 MethodImplUniqueId *impl = g_new (MethodImplUniqueId, 1);
3812 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
3814 impl->klass = data [MONO_METHODIMPL_CLASS];
3815 impl->method_declaration = data [MONO_METHODIMPL_DECLARATION];
3817 if (g_hash_table_lookup (unique_impls, impl)) {
3818 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("MethodImpl table row %d has duplicate for tuple (0x%x, 0x%x)", i, impl->klass, impl->method_declaration));
3819 g_hash_table_destroy (unique_impls);
3820 g_free (impl);
3821 return;
3823 g_hash_table_insert (unique_impls, impl, GUINT_TO_POINTER (1));
3826 g_hash_table_destroy (unique_impls);
3830 static void
3831 verify_tables_data_global_constraints (VerifyContext *ctx)
3833 verify_typedef_table_global_constraints (ctx);
3836 static void
3837 verify_tables_data_global_constraints_full (VerifyContext *ctx)
3839 verify_typeref_table (ctx);
3840 verify_typeref_table_global_constraints (ctx);
3841 verify_methodimpl_table_global_constraints (ctx);
3844 static void
3845 verify_tables_data (VerifyContext *ctx)
3847 OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
3848 guint32 size = 0, tables_offset;
3849 int i;
3851 for (i = 0; i < 0x2D; ++i) {
3852 MonoTableInfo *table = &ctx->image->tables [i];
3853 guint32 tmp_size;
3854 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
3855 if (tmp_size < size) {
3856 size = 0;
3857 break;
3859 size = tmp_size;
3862 if (size == 0)
3863 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
3865 tables_offset = ctx->image->tables_base - ctx->data;
3866 if (!bounds_check_offset (&tables_area, tables_offset, size))
3867 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)));
3869 verify_module_table (ctx);
3870 CHECK_ERROR ();
3871 /*Obfuscators love to place broken stuff in the typeref table
3872 verify_typeref_table (ctx);
3873 CHECK_ERROR ();*/
3874 verify_typedef_table (ctx);
3875 CHECK_ERROR ();
3876 verify_field_table (ctx);
3877 CHECK_ERROR ();
3878 verify_method_table (ctx);
3879 CHECK_ERROR ();
3880 verify_param_table (ctx);
3881 CHECK_ERROR ();
3882 verify_interfaceimpl_table (ctx);
3883 CHECK_ERROR ();
3884 verify_memberref_table (ctx);
3885 CHECK_ERROR ();
3886 verify_constant_table (ctx);
3887 CHECK_ERROR ();
3888 verify_cattr_table (ctx);
3889 CHECK_ERROR ();
3890 verify_field_marshal_table (ctx);
3891 CHECK_ERROR ();
3892 verify_decl_security_table (ctx);
3893 CHECK_ERROR ();
3894 verify_class_layout_table (ctx);
3895 CHECK_ERROR ();
3896 verify_field_layout_table (ctx);
3897 CHECK_ERROR ();
3898 verify_standalonesig_table (ctx);
3899 CHECK_ERROR ();
3900 verify_eventmap_table (ctx);
3901 CHECK_ERROR ();
3902 verify_event_table (ctx);
3903 CHECK_ERROR ();
3904 verify_propertymap_table (ctx);
3905 CHECK_ERROR ();
3906 verify_property_table (ctx);
3907 CHECK_ERROR ();
3908 verify_methodimpl_table (ctx);
3909 CHECK_ERROR ();
3910 verify_moduleref_table (ctx);
3911 CHECK_ERROR ();
3912 verify_typespec_table (ctx);
3913 CHECK_ERROR ();
3914 verify_implmap_table (ctx);
3915 CHECK_ERROR ();
3916 verify_fieldrva_table (ctx);
3917 CHECK_ERROR ();
3918 verify_assembly_table (ctx);
3919 CHECK_ERROR ();
3920 verify_assemblyref_table (ctx);
3921 CHECK_ERROR ();
3922 verify_file_table (ctx);
3923 CHECK_ERROR ();
3924 verify_exportedtype_table (ctx);
3925 CHECK_ERROR ();
3926 verify_manifest_resource_table (ctx);
3927 CHECK_ERROR ();
3928 verify_nested_class_table (ctx);
3929 CHECK_ERROR ();
3930 verify_generic_param_table (ctx);
3931 CHECK_ERROR ();
3932 verify_method_spec_table (ctx);
3933 CHECK_ERROR ();
3934 verify_generic_param_constraint_table (ctx);
3935 CHECK_ERROR ();
3936 verify_tables_data_global_constraints (ctx);
3939 static void
3940 init_verify_context (VerifyContext *ctx, MonoImage *image)
3942 memset (ctx, 0, sizeof (VerifyContext));
3943 ctx->image = image;
3944 ctx->report_error = TRUE;
3945 ctx->report_warning = FALSE; //export this setting in the API
3946 ctx->valid = 1;
3947 ctx->size = m_image_get_raw_data_len (image);
3948 ctx->data = m_image_get_raw_data (image);
3951 static gboolean
3952 cleanup_context (VerifyContext *ctx, MonoError *error)
3954 g_free (ctx->sections);
3955 if (ctx->errors) {
3956 MonoVerifyInfo *info = (MonoVerifyInfo *)ctx->errors->data;
3957 mono_error_set_bad_image (error, ctx->image, "%s", info->message);
3958 mono_free_verify_list (ctx->errors);
3960 return ctx->valid;
3963 gboolean
3964 mono_verifier_verify_pe_data (MonoImage *image, MonoError *error)
3966 VerifyContext ctx;
3968 error_init (error);
3970 if (!mono_verifier_is_enabled_for_image (image))
3971 return TRUE;
3973 init_verify_context (&ctx, image);
3974 ctx.stage = STAGE_PE;
3976 verify_msdos_header (&ctx);
3977 CHECK_STATE();
3978 verify_pe_header (&ctx);
3979 CHECK_STATE();
3980 verify_pe_optional_header (&ctx);
3981 CHECK_STATE();
3982 load_section_table (&ctx);
3983 CHECK_STATE();
3984 load_data_directories (&ctx);
3985 CHECK_STATE();
3986 verify_import_table (&ctx);
3987 CHECK_STATE();
3988 /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
3989 verify_resources_table (&ctx);
3991 cleanup:
3992 return cleanup_context (&ctx, error);
3995 gboolean
3996 mono_verifier_verify_cli_data (MonoImage *image, MonoError *error)
3998 VerifyContext ctx;
4000 error_init (error);
4002 if (!mono_verifier_is_enabled_for_image (image))
4003 return TRUE;
4005 init_verify_context (&ctx, image);
4006 ctx.stage = STAGE_CLI;
4008 verify_cli_header (&ctx);
4009 CHECK_STATE();
4010 verify_metadata_header (&ctx);
4011 CHECK_STATE();
4012 verify_tables_schema (&ctx);
4014 cleanup:
4015 return cleanup_context (&ctx, error);
4020 * Verifies basic table constraints such as global table invariants (sorting, field monotonicity, etc).
4021 * Other verification checks are meant to be done lazily by the runtime. Those include:
4022 * blob items (signatures, method headers, custom attributes, etc)
4023 * type semantics related
4024 * vtable related
4025 * stuff that should not block other pieces from running such as bad types/methods/fields/etc.
4027 * The whole idea is that if this succeed the runtime is free to play around safely but any complex
4028 * operation still need more checking.
4030 gboolean
4031 mono_verifier_verify_table_data (MonoImage *image, MonoError *error)
4033 VerifyContext ctx;
4035 error_init (error);
4037 if (!mono_verifier_is_enabled_for_image (image))
4038 return TRUE;
4040 init_verify_context (&ctx, image);
4041 ctx.stage = STAGE_TABLES;
4043 verify_tables_data (&ctx);
4045 return cleanup_context (&ctx, error);
4050 * Verifies all other constraints.
4052 gboolean
4053 mono_verifier_verify_full_table_data (MonoImage *image, MonoError *error)
4055 VerifyContext ctx;
4057 error_init (error);
4059 if (!mono_verifier_is_enabled_for_image (image))
4060 return TRUE;
4062 init_verify_context (&ctx, image);
4063 ctx.stage = STAGE_TABLES;
4065 verify_typedef_table_full (&ctx);
4066 CHECK_STATE ();
4067 verify_field_table_full (&ctx);
4068 CHECK_STATE ();
4069 verify_method_table_full (&ctx);
4070 CHECK_STATE ();
4071 verify_memberref_table_full (&ctx);
4072 CHECK_STATE ();
4073 verify_cattr_table_full (&ctx);
4074 CHECK_STATE ();
4075 verify_field_marshal_table_full (&ctx);
4076 CHECK_STATE ();
4077 verify_decl_security_table_full (&ctx);
4078 CHECK_STATE ();
4079 verify_standalonesig_table_full (&ctx);
4080 CHECK_STATE ();
4081 verify_event_table_full (&ctx);
4082 CHECK_STATE ();
4083 verify_typespec_table_full (&ctx);
4084 CHECK_STATE ();
4085 verify_method_spec_table_full (&ctx);
4086 CHECK_STATE ();
4087 verify_tables_data_global_constraints_full (&ctx);
4089 cleanup:
4090 return cleanup_context (&ctx, error);
4093 gboolean
4094 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, MonoError *error)
4096 VerifyContext ctx;
4098 error_init (error);
4100 if (!mono_verifier_is_enabled_for_image (image))
4101 return TRUE;
4103 init_verify_context (&ctx, image);
4104 ctx.stage = STAGE_TABLES;
4106 is_valid_field_signature (&ctx, offset);
4107 return cleanup_context (&ctx, error);
4110 gboolean
4111 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, MonoError *error)
4113 VerifyContext ctx;
4114 guint32 locals_token;
4116 error_init (error);
4118 if (!mono_verifier_is_enabled_for_image (image))
4119 return TRUE;
4121 init_verify_context (&ctx, image);
4122 ctx.stage = STAGE_TABLES;
4124 is_valid_method_header (&ctx, offset, &locals_token);
4125 if (locals_token) {
4126 guint32 sig_offset = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_STANDALONESIG], locals_token - 1, MONO_STAND_ALONE_SIGNATURE);
4127 is_valid_standalonesig_blob (&ctx, sig_offset);
4130 return cleanup_context (&ctx, error);
4133 gboolean
4134 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, MonoError *error)
4136 VerifyContext ctx;
4138 error_init (error);
4140 if (!mono_verifier_is_enabled_for_image (image))
4141 return TRUE;
4143 init_verify_context (&ctx, image);
4144 ctx.stage = STAGE_TABLES;
4146 is_valid_method_signature (&ctx, offset);
4147 /*XXX This returns a bad image exception, it might be the case that the right exception is method load.*/
4148 return cleanup_context (&ctx, error);
4151 gboolean
4152 mono_verifier_verify_memberref_method_signature (MonoImage *image, guint32 offset, MonoError *error)
4154 VerifyContext ctx;
4156 error_init (error);
4158 if (!mono_verifier_is_enabled_for_image (image))
4159 return TRUE;
4161 init_verify_context (&ctx, image);
4162 ctx.stage = STAGE_TABLES;
4164 is_valid_memberref_method_signature (&ctx, offset);
4165 return cleanup_context (&ctx, error);
4168 gboolean
4169 mono_verifier_verify_memberref_field_signature (MonoImage *image, guint32 offset, MonoError *error)
4171 VerifyContext ctx;
4173 error_init (error);
4175 if (!mono_verifier_is_enabled_for_image (image))
4176 return TRUE;
4178 init_verify_context (&ctx, image);
4179 ctx.stage = STAGE_TABLES;
4181 is_valid_field_signature (&ctx, offset);
4182 return cleanup_context (&ctx, error);
4185 gboolean
4186 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, MonoError *error)
4188 VerifyContext ctx;
4190 error_init (error);
4192 if (!mono_verifier_is_enabled_for_image (image))
4193 return TRUE;
4195 init_verify_context (&ctx, image);
4196 ctx.stage = STAGE_TABLES;
4198 is_valid_standalonesig_blob (&ctx, offset);
4199 return cleanup_context (&ctx, error);
4202 gboolean
4203 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, MonoError *error)
4205 VerifyContext ctx;
4207 error_init (error);
4210 if (!mono_verifier_is_enabled_for_image (image))
4211 return TRUE;
4213 init_verify_context (&ctx, image);
4214 ctx.stage = STAGE_TABLES;
4215 ctx.token = token;
4217 is_valid_typespec_blob (&ctx, offset);
4218 return cleanup_context (&ctx, error);
4221 gboolean
4222 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, MonoError *error)
4224 VerifyContext ctx;
4226 error_init (error);
4228 if (!mono_verifier_is_enabled_for_image (image))
4229 return TRUE;
4231 init_verify_context (&ctx, image);
4232 ctx.stage = STAGE_TABLES;
4234 is_valid_methodspec_blob (&ctx, offset);
4235 return cleanup_context (&ctx, error);
4238 static void
4239 verify_user_string (VerifyContext *ctx, guint32 offset)
4241 OffsetAndSize heap_us = get_metadata_stream (ctx, &ctx->image->heap_us);
4242 guint32 entry_size, bytes;
4244 if (heap_us.size < offset)
4245 ADD_ERROR (ctx, g_strdup ("User string offset beyond heap_us size"));
4247 if (!decode_value (ctx->data + offset + heap_us.offset, heap_us.size - heap_us.offset, &entry_size, &bytes))
4248 ADD_ERROR (ctx, g_strdup ("Could not decode user string blob size"));
4250 if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
4251 ADD_ERROR (ctx, g_strdup ("User string size overflow"));
4253 entry_size += bytes;
4255 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, heap_us.size))
4256 ADD_ERROR (ctx, g_strdup ("User string oveflow heap_us"));
4259 gboolean
4260 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, MonoError *error)
4262 VerifyContext ctx;
4264 error_init (error);
4266 if (!mono_verifier_is_enabled_for_image (image))
4267 return TRUE;
4269 init_verify_context (&ctx, image);
4270 ctx.stage = STAGE_TABLES;
4272 verify_user_string (&ctx, offset);
4274 return cleanup_context (&ctx, error);
4277 gboolean
4278 mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, MonoError *error)
4280 VerifyContext ctx;
4282 error_init (error);
4284 if (!mono_verifier_is_enabled_for_image (image))
4285 return TRUE;
4287 init_verify_context (&ctx, image);
4288 ctx.stage = STAGE_TABLES;
4290 is_valid_cattr_blob (&ctx, offset);
4292 return cleanup_context (&ctx, error);
4296 //FIXME this should raise a System.Reflection.CustomAttributeFormatException
4297 gboolean
4298 mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, MonoError *error)
4300 VerifyContext ctx;
4302 error_init (error);
4304 if (!mono_verifier_is_enabled_for_image (image))
4305 return TRUE;
4307 init_verify_context (&ctx, image);
4308 ctx.stage = STAGE_TABLES;
4310 is_valid_cattr_content (&ctx, ctor, (const char*)data, size);
4312 return cleanup_context (&ctx, error);
4315 gboolean
4316 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
4318 MonoMethodSignature *original_sig;
4319 if (!mono_verifier_is_enabled_for_image (image))
4320 return TRUE;
4322 original_sig = mono_method_signature_internal (method);
4323 if (original_sig->call_convention == MONO_CALL_VARARG) {
4324 if (original_sig->hasthis != signature->hasthis)
4325 return FALSE;
4326 if (original_sig->call_convention != signature->call_convention)
4327 return FALSE;
4328 if (original_sig->explicit_this != signature->explicit_this)
4329 return FALSE;
4330 if (original_sig->pinvoke != signature->pinvoke)
4331 return FALSE;
4332 if (original_sig->sentinelpos != signature->sentinelpos)
4333 return FALSE;
4334 } else if (!mono_metadata_signature_equal (signature, original_sig)) {
4335 return FALSE;
4338 return TRUE;
4341 gboolean
4342 mono_verifier_verify_typeref_row (MonoImage *image, guint32 row, MonoError *error)
4344 MonoTableInfo *table = &image->tables [MONO_TABLE_TYPEREF];
4345 guint32 data [MONO_TYPEREF_SIZE];
4347 error_init (error);
4349 if (!mono_verifier_is_enabled_for_image (image))
4350 return TRUE;
4352 if (row >= table->rows) {
4353 mono_error_set_bad_image (error, image, "Invalid typeref row %d - table has %d rows", row, table->rows);
4354 return FALSE;
4357 mono_metadata_decode_row (table, row, data, MONO_TYPEREF_SIZE);
4358 if (!is_valid_coded_index_with_image (image, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE])) {
4359 mono_error_set_bad_image (error, image, "Invalid typeref row %d coded index 0x%08x", row, data [MONO_TYPEREF_SCOPE]);
4360 return FALSE;
4363 if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE])) {
4364 mono_error_set_bad_image (error, image, "The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", row);
4365 return FALSE;
4368 if (!data [MONO_TYPEREF_NAME] || !is_valid_string_full_with_image (image, data [MONO_TYPEREF_NAME], FALSE)) {
4369 mono_error_set_bad_image (error, image, "Invalid typeref row %d name token 0x%08x", row, data [MONO_TYPEREF_NAME]);
4370 return FALSE;
4373 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_string_full_with_image (image, data [MONO_TYPEREF_NAMESPACE], FALSE)) {
4374 mono_error_set_bad_image (error, image, "Invalid typeref row %d namespace token 0x%08x", row, data [MONO_TYPEREF_NAMESPACE]);
4375 return FALSE;
4378 return TRUE;
4381 /*Perform additional verification including metadata ones*/
4382 gboolean
4383 mono_verifier_verify_methodimpl_row (MonoImage *image, guint32 row, MonoError *error)
4385 MonoMethod *declaration, *body;
4386 MonoMethodSignature *body_sig, *decl_sig;
4387 MonoTableInfo *table = &image->tables [MONO_TABLE_METHODIMPL];
4388 guint32 data [MONO_METHODIMPL_SIZE];
4390 error_init (error);
4392 if (!mono_verifier_is_enabled_for_image (image))
4393 return TRUE;
4395 if (row >= table->rows) {
4396 mono_error_set_bad_image (error, image, "Invalid methodimpl row %d - table has %d rows", row, table->rows);
4397 return FALSE;
4400 mono_metadata_decode_row (table, row, data, MONO_METHODIMPL_SIZE);
4402 body = mono_method_from_method_def_or_ref (image, data [MONO_METHODIMPL_BODY], NULL, error);
4403 if (!body)
4404 return FALSE;
4406 declaration = mono_method_from_method_def_or_ref (image, data [MONO_METHODIMPL_DECLARATION], NULL, error);
4407 if (!declaration)
4408 return FALSE;
4410 /* FIXME
4411 mono_class_setup_supertypes (class);
4412 if (!mono_class_has_parent (class, body->klass)) {
4413 mono_error_set_bad_image (error, image, "Invalid methodimpl body doesn't belong to parent for row %x", row);
4414 return FALSE;
4417 if (!(body_sig = mono_method_signature_checked (body, error))) {
4418 return FALSE;
4421 if (!(decl_sig = mono_method_signature_checked (declaration, error))) {
4422 return FALSE;
4425 if (!mono_verifier_is_signature_compatible (decl_sig, body_sig)) {
4426 mono_error_set_bad_image (error, image, "Invalid methodimpl body signature not compatible with declaration row %x", row);
4427 return FALSE;
4430 return TRUE;
4433 #else
4434 gboolean
4435 mono_verifier_verify_table_data (MonoImage *image, MonoError *error)
4437 error_init (error);
4438 return TRUE;
4441 gboolean
4442 mono_verifier_verify_cli_data (MonoImage *image, MonoError *error)
4444 error_init (error);
4445 return TRUE;
4448 gboolean
4449 mono_verifier_verify_pe_data (MonoImage *image, MonoError *error)
4451 error_init (error);
4452 return TRUE;
4455 gboolean
4456 mono_verifier_verify_full_table_data (MonoImage *image, MonoError *error)
4458 error_init (error);
4459 return TRUE;
4462 gboolean
4463 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, MonoError *error)
4465 error_init (error);
4466 return TRUE;
4469 gboolean
4470 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, MonoError *error)
4472 error_init (error);
4473 return TRUE;
4476 gboolean
4477 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, MonoError *error)
4479 error_init (error);
4480 return TRUE;
4483 gboolean
4484 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, MonoError *error)
4486 error_init (error);
4487 return TRUE;
4490 gboolean
4491 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, MonoError *error)
4493 error_init (error);
4494 return TRUE;
4497 gboolean
4498 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, MonoError *error)
4500 error_init (error);
4501 return TRUE;
4504 gboolean
4505 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, MonoError *error)
4507 error_init (error);
4508 return TRUE;
4511 gboolean
4512 mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, MonoError *error)
4514 error_init (error);
4515 return TRUE;
4518 gboolean
4519 mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, MonoError *error)
4521 error_init (error);
4522 return TRUE;
4525 gboolean
4526 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
4528 return TRUE;
4532 gboolean
4533 mono_verifier_verify_typeref_row (MonoImage *image, guint32 row, MonoError *error)
4535 error_init (error);
4536 return TRUE;
4539 gboolean
4540 mono_verifier_verify_methodimpl_row (MonoImage *image, guint32 row, MonoError *error)
4542 error_init (error);
4543 return TRUE;
4546 gboolean
4547 mono_verifier_verify_memberref_method_signature (MonoImage *image, guint32 offset, MonoError *error)
4549 error_init (error);
4550 return TRUE;
4553 gboolean
4554 mono_verifier_verify_memberref_field_signature (MonoImage *image, guint32 offset, MonoError *error)
4556 error_init (error);
4557 return TRUE;
4560 #endif /* DISABLE_VERIFIER */