[verifier] Allow byref in PropertySig blobs. Fixes #59180
[mono-project.git] / mono / metadata / metadata-verify.c
blobe898178e00a1532a253acbf3adea8e23787c6fd9
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 <mono/metadata/object-internals.h>
12 #include <mono/metadata/verify.h>
13 #include <mono/metadata/verify-internals.h>
14 #include <mono/metadata/opcodes.h>
15 #include <mono/metadata/tabledefs.h>
16 #include <mono/metadata/reflection.h>
17 #include <mono/metadata/debug-helpers.h>
18 #include <mono/metadata/mono-endian.h>
19 #include <mono/metadata/metadata.h>
20 #include <mono/metadata/metadata-internals.h>
21 #include <mono/metadata/class-internals.h>
22 #include <mono/metadata/tokentype.h>
23 #include <mono/metadata/security-manager.h>
24 #include <mono/metadata/security-core-clr.h>
25 #include <mono/metadata/cil-coff.h>
26 #include <mono/metadata/attrdefs.h>
27 #include <mono/utils/strenc.h>
28 #include <mono/utils/mono-error-internals.h>
29 #include <mono/utils/bsearch.h>
30 #include <string.h>
31 //#include <signal.h>
32 #include <ctype.h>
34 #ifndef DISABLE_VERIFIER
36 TODO add fail fast mode
37 TODO add PE32+ support
38 TODO verify the entry point RVA and content.
39 TODO load_section_table and load_data_directories must take PE32+ into account
40 TODO add section relocation support
41 TODO verify the relocation table, since we really don't use, no need so far.
42 TODO do full PECOFF resources verification
43 TODO verify in the CLI header entry point and resources
44 TODO implement null token typeref validation
45 TODO verify table wide invariants for typedef (sorting and uniqueness)
46 TODO implement proper authenticode data directory validation
47 TODO verify properties that require multiple tables to be valid
48 FIXME use subtraction based bounds checking to avoid overflows
49 FIXME get rid of metadata_streams and other fields from VerifyContext
52 #ifdef MONO_VERIFIER_DEBUG
53 #define VERIFIER_DEBUG(code) do { code; } while (0)
54 #else
55 #define VERIFIER_DEBUG(code)
56 #endif
58 #define INVALID_OFFSET ((guint32)-1)
59 #define INVALID_ADDRESS 0xffffffff
61 enum {
62 STAGE_PE,
63 STAGE_CLI,
64 STAGE_TABLES
67 enum {
68 IMPORT_TABLE_IDX = 1,
69 RESOURCE_TABLE_IDX = 2,
70 CERTIFICATE_TABLE_IDX = 4,
71 RELOCATION_TABLE_IDX = 5,
72 IAT_IDX = 12,
73 CLI_HEADER_IDX = 14,
76 enum {
77 STRINGS_STREAM,
78 USER_STRINGS_STREAM,
79 BLOB_STREAM,
80 GUID_STREAM,
81 TILDE_STREAM
85 #define INVALID_TABLE (0xFF)
86 /*format: number of bits, number of tables, tables{n. tables} */
87 const static unsigned char coded_index_desc[] = {
88 #define TYPEDEF_OR_REF_DESC (0)
89 2, /*bits*/
90 3, /*tables*/
91 MONO_TABLE_TYPEDEF,
92 MONO_TABLE_TYPEREF,
93 MONO_TABLE_TYPESPEC,
95 #define HAS_CONSTANT_DESC (TYPEDEF_OR_REF_DESC + 5)
96 2, /*bits*/
97 3, /*tables*/
98 MONO_TABLE_FIELD,
99 MONO_TABLE_PARAM,
100 MONO_TABLE_PROPERTY,
102 #define HAS_CATTR_DESC (HAS_CONSTANT_DESC + 5)
103 5, /*bits*/
104 20, /*tables*/
105 MONO_TABLE_METHOD,
106 MONO_TABLE_FIELD,
107 MONO_TABLE_TYPEREF,
108 MONO_TABLE_TYPEDEF,
109 MONO_TABLE_PARAM,
110 MONO_TABLE_INTERFACEIMPL,
111 MONO_TABLE_MEMBERREF,
112 MONO_TABLE_MODULE,
113 MONO_TABLE_DECLSECURITY,
114 MONO_TABLE_PROPERTY,
115 MONO_TABLE_EVENT,
116 MONO_TABLE_STANDALONESIG,
117 MONO_TABLE_MODULEREF,
118 MONO_TABLE_TYPESPEC,
119 MONO_TABLE_ASSEMBLY,
120 MONO_TABLE_ASSEMBLYREF,
121 MONO_TABLE_FILE,
122 MONO_TABLE_EXPORTEDTYPE,
123 MONO_TABLE_MANIFESTRESOURCE,
124 MONO_TABLE_GENERICPARAM,
126 #define HAS_FIELD_MARSHAL_DESC (HAS_CATTR_DESC + 22)
127 1, /*bits*/
128 2, /*tables*/
129 MONO_TABLE_FIELD,
130 MONO_TABLE_PARAM,
132 #define HAS_DECL_SECURITY_DESC (HAS_FIELD_MARSHAL_DESC + 4)
133 2, /*bits*/
134 3, /*tables*/
135 MONO_TABLE_TYPEDEF,
136 MONO_TABLE_METHOD,
137 MONO_TABLE_ASSEMBLY,
139 #define MEMBERREF_PARENT_DESC (HAS_DECL_SECURITY_DESC + 5)
140 3, /*bits*/
141 5, /*tables*/
142 MONO_TABLE_TYPEDEF,
143 MONO_TABLE_TYPEREF,
144 MONO_TABLE_MODULEREF,
145 MONO_TABLE_METHOD,
146 MONO_TABLE_TYPESPEC,
148 #define HAS_SEMANTICS_DESC (MEMBERREF_PARENT_DESC + 7)
149 1, /*bits*/
150 2, /*tables*/
151 MONO_TABLE_EVENT,
152 MONO_TABLE_PROPERTY,
154 #define METHODDEF_OR_REF_DESC (HAS_SEMANTICS_DESC + 4)
155 1, /*bits*/
156 2, /*tables*/
157 MONO_TABLE_METHOD,
158 MONO_TABLE_MEMBERREF,
160 #define MEMBER_FORWARDED_DESC (METHODDEF_OR_REF_DESC + 4)
161 1, /*bits*/
162 2, /*tables*/
163 MONO_TABLE_FIELD,
164 MONO_TABLE_METHOD,
166 #define IMPLEMENTATION_DESC (MEMBER_FORWARDED_DESC + 4)
167 2, /*bits*/
168 3, /*tables*/
169 MONO_TABLE_FILE,
170 MONO_TABLE_ASSEMBLYREF,
171 MONO_TABLE_EXPORTEDTYPE,
173 #define CATTR_TYPE_DESC (IMPLEMENTATION_DESC + 5)
174 3, /*bits*/
175 5, /*tables*/
176 INVALID_TABLE,
177 INVALID_TABLE,
178 MONO_TABLE_METHOD,
179 MONO_TABLE_MEMBERREF,
180 INVALID_TABLE,
182 #define RES_SCOPE_DESC (CATTR_TYPE_DESC + 7)
183 2, /*bits*/
184 4, /*tables*/
185 MONO_TABLE_MODULE,
186 MONO_TABLE_MODULEREF,
187 MONO_TABLE_ASSEMBLYREF,
188 MONO_TABLE_TYPEREF,
190 #define TYPE_OR_METHODDEF_DESC (RES_SCOPE_DESC + 6)
191 1, /*bits*/
192 2, /*tables*/
193 MONO_TABLE_TYPEDEF,
194 MONO_TABLE_METHOD
197 typedef struct {
198 guint32 rva;
199 guint32 size;
200 guint32 translated_offset;
201 } DataDirectory;
203 typedef struct {
204 guint32 offset;
205 guint32 size;
206 } OffsetAndSize;
208 typedef struct {
209 guint32 baseRVA;
210 guint32 baseOffset;
211 guint32 size;
212 guint32 rellocationsRVA;
213 guint16 numberOfRelocations;
214 } SectionHeader;
216 typedef struct {
217 guint32 row_count;
218 guint32 row_size;
219 guint32 offset;
220 } TableInfo;
222 typedef struct {
223 const char *data;
224 guint32 size, token;
225 GSList *errors;
226 int valid;
227 MonoImage *image;
228 gboolean report_error;
229 gboolean report_warning;
230 int stage;
232 DataDirectory data_directories [16];
233 guint32 section_count;
234 SectionHeader *sections;
236 OffsetAndSize metadata_streams [5]; //offset from begin of the image
237 } VerifyContext;
239 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception) \
240 do { \
241 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
242 vinfo->info.status = __status; \
243 vinfo->info.message = ( __msg); \
244 vinfo->exception_type = (__exception); \
245 (__ctx)->errors = g_slist_prepend ((__ctx)->errors, vinfo); \
246 } while (0)
248 #define ADD_WARNING(__ctx, __msg) \
249 do { \
250 if ((__ctx)->report_warning) { \
251 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_WARNING, MONO_EXCEPTION_INVALID_PROGRAM); \
252 (__ctx)->valid = 0; \
253 return; \
255 } while (0)
257 #define ADD_ERROR_NO_RETURN(__ctx, __msg) \
258 do { \
259 if ((__ctx)->report_error) \
260 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
261 (__ctx)->valid = 0; \
262 } while (0)
264 #define ADD_ERROR(__ctx, __msg) \
265 do { \
266 if ((__ctx)->report_error) \
267 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
268 (__ctx)->valid = 0; \
269 return; \
270 } while (0)
272 #define FAIL(__ctx, __msg) \
273 do { \
274 if ((__ctx)->report_error) \
275 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
276 (__ctx)->valid = 0; \
277 return FALSE; \
278 } while (0)
280 #define CHECK_STATE() do { if (!ctx.valid) goto cleanup; } while (0)
282 #define CHECK_ERROR() do { if (!ctx->valid) return; } while (0)
284 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
285 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
287 #if SIZEOF_VOID_P == 4
288 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
289 #else
290 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
291 #endif
293 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
294 #define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
296 static const char *
297 dword_align (const char *ptr)
299 #if SIZEOF_VOID_P == 8
300 return (const char *) (((guint64) (ptr + 3)) & ~3);
301 #else
302 return (const char *) (((guint32) (ptr + 3)) & ~3);
303 #endif
306 static void
307 add_from_mono_error (VerifyContext *ctx, MonoError *error)
309 if (mono_error_ok (error))
310 return;
312 ADD_ERROR (ctx, g_strdup (mono_error_get_message (error)));
313 mono_error_cleanup (error);
316 static guint32
317 pe_signature_offset (VerifyContext *ctx)
319 return read32 (ctx->data + 0x3c);
322 static guint32
323 pe_header_offset (VerifyContext *ctx)
325 return read32 (ctx->data + 0x3c) + 4;
328 static gboolean
329 bounds_check_virtual_address (VerifyContext *ctx, guint32 rva, guint32 size)
331 int i;
333 if (rva + size < rva) //overflow
334 return FALSE;
336 if (ctx->stage > STAGE_PE) {
337 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)ctx->image->image_info;
338 const int top = iinfo->cli_section_count;
339 MonoSectionTable *tables = iinfo->cli_section_tables;
340 int i;
342 for (i = 0; i < top; i++) {
343 guint32 base = tables->st_virtual_address;
344 guint32 end = base + tables->st_raw_data_size;
346 if (rva >= base && rva + size <= end)
347 return TRUE;
349 /*if ((addr >= tables->st_virtual_address) &&
350 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
352 return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
354 tables++;
356 return FALSE;
359 if (!ctx->sections)
360 return FALSE;
362 for (i = 0; i < ctx->section_count; ++i) {
363 guint32 base = ctx->sections [i].baseRVA;
364 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
365 if (rva >= base && rva + size <= end)
366 return TRUE;
368 return FALSE;
371 static gboolean
372 bounds_check_datadir (DataDirectory *dir, guint32 offset, guint32 size)
374 if (dir->translated_offset > offset)
375 return FALSE;
376 if (dir->size < size)
377 return FALSE;
378 return offset + size <= dir->translated_offset + dir->size;
381 static gboolean
382 bounds_check_offset (OffsetAndSize *off, guint32 offset, guint32 size)
384 if (off->offset > offset)
385 return FALSE;
387 if (off->size < size)
388 return FALSE;
390 return offset + size <= off->offset + off->size;
393 static guint32
394 translate_rva (VerifyContext *ctx, guint32 rva)
396 int i;
398 if (ctx->stage > STAGE_PE)
399 return mono_cli_rva_image_map (ctx->image, rva);
401 if (!ctx->sections)
402 return FALSE;
404 for (i = 0; i < ctx->section_count; ++i) {
405 guint32 base = ctx->sections [i].baseRVA;
406 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
407 if (rva >= base && rva <= end) {
408 guint32 res = (rva - base) + ctx->sections [i].baseOffset;
409 /* double check */
410 return res >= ctx->size ? INVALID_OFFSET : res;
414 return INVALID_OFFSET;
417 static void
418 verify_msdos_header (VerifyContext *ctx)
420 guint32 lfanew;
421 if (ctx->size < 128)
422 ADD_ERROR (ctx, g_strdup ("Not enough space for the MS-DOS header"));
423 if (ctx->data [0] != 0x4d || ctx->data [1] != 0x5a)
424 ADD_ERROR (ctx, g_strdup ("Invalid MS-DOS watermark"));
425 lfanew = pe_signature_offset (ctx);
426 if (lfanew > ctx->size - 4)
427 ADD_ERROR (ctx, g_strdup ("MS-DOS lfanew offset points to outside of the file"));
430 static void
431 verify_pe_header (VerifyContext *ctx)
433 guint32 offset = pe_signature_offset (ctx);
434 const char *pe_header = ctx->data + offset;
435 if (pe_header [0] != 'P' || pe_header [1] != 'E' ||pe_header [2] != 0 ||pe_header [3] != 0)
436 ADD_ERROR (ctx, g_strdup ("Invalid PE header watermark"));
437 pe_header += 4;
438 offset += 4;
440 if (offset > ctx->size - 20)
441 ADD_ERROR (ctx, g_strdup ("File with truncated pe header"));
442 if (read16 (pe_header) != 0x14c)
443 ADD_ERROR (ctx, g_strdup ("Invalid PE header Machine value"));
446 static void
447 verify_pe_optional_header (VerifyContext *ctx)
449 guint32 offset = pe_header_offset (ctx);
450 guint32 header_size, file_alignment;
451 const char *pe_header = ctx->data + offset;
452 const char *pe_optional_header = pe_header + 20;
454 header_size = read16 (pe_header + 16);
455 offset += 20;
457 if (header_size < 2) /*must be at least 2 or we won't be able to read magic*/
458 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
460 if (offset > ctx->size - header_size || header_size > ctx->size)
461 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
463 if (read16 (pe_optional_header) == 0x10b) {
464 if (header_size != 224)
465 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header size %d", header_size));
467 /* LAMESPEC MS plays around this value and ignore it during validation
468 if (read32 (pe_optional_header + 28) != 0x400000)
469 ADD_ERROR (ctx, g_strdup_printf ("Invalid Image base %x", read32 (pe_optional_header + 28)));*/
470 if (read32 (pe_optional_header + 32) != 0x2000)
471 ADD_ERROR (ctx, g_strdup_printf ("Invalid Section Aligmnent %x", read32 (pe_optional_header + 32)));
472 file_alignment = read32 (pe_optional_header + 36);
473 if (file_alignment != 0x200 && file_alignment != 0x1000)
474 ADD_ERROR (ctx, g_strdup_printf ("Invalid file Aligmnent %x", file_alignment));
475 /* All the junk in the middle is irrelevant, specially for mono. */
476 if (read32 (pe_optional_header + 92) > 0x10)
477 ADD_ERROR (ctx, g_strdup_printf ("Too many data directories %x", read32 (pe_optional_header + 92)));
478 } else {
479 if (read16 (pe_optional_header) == 0x20B)
480 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle PE32+"));
481 else
482 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header magic %d", read16 (pe_optional_header)));
486 static void
487 load_section_table (VerifyContext *ctx)
489 int i;
490 SectionHeader *sections;
491 guint32 offset = pe_header_offset (ctx);
492 const char *ptr = ctx->data + offset;
493 guint16 num_sections = ctx->section_count = read16 (ptr + 2);
495 offset += 244;/*FIXME, this constant is different under PE32+*/
496 ptr += 244;
498 if (num_sections * 40 > ctx->size - offset)
499 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
501 sections = ctx->sections = g_new0 (SectionHeader, num_sections);
502 for (i = 0; i < num_sections; ++i) {
503 sections [i].size = read32 (ptr + 8);
504 sections [i].baseRVA = read32 (ptr + 12);
505 sections [i].baseOffset = read32 (ptr + 20);
506 sections [i].rellocationsRVA = read32 (ptr + 24);
507 sections [i].numberOfRelocations = read16 (ptr + 32);
508 ptr += 40;
511 ptr = ctx->data + offset; /*reset it to the beggining*/
512 for (i = 0; i < num_sections; ++i) {
513 guint32 raw_size, flags;
514 if (sections [i].baseOffset == 0)
515 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with intialized data only"));
516 if (sections [i].baseOffset >= ctx->size)
517 ADD_ERROR (ctx, g_strdup_printf ("Invalid PointerToRawData %x points beyond EOF", sections [i].baseOffset));
518 if (sections [i].size > ctx->size - sections [i].baseOffset)
519 ADD_ERROR (ctx, g_strdup ("Invalid VirtualSize points beyond EOF"));
521 raw_size = read32 (ptr + 16);
522 if (raw_size < sections [i].size)
523 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with SizeOfRawData < VirtualSize"));
525 if (raw_size > ctx->size - sections [i].baseOffset)
526 ADD_ERROR (ctx, g_strdup_printf ("Invalid SizeOfRawData %x points beyond EOF", raw_size));
528 if (sections [i].rellocationsRVA || sections [i].numberOfRelocations)
529 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't handle section relocation"));
531 flags = read32 (ptr + 36);
532 /*TODO 0xFE0000E0 is all flags from cil-coff.h OR'd. Make it a less magical number*/
533 if (flags == 0 || (flags & ~0xFE0000E0) != 0)
534 ADD_ERROR (ctx, g_strdup_printf ("Invalid section flags %x", flags));
536 ptr += 40;
540 static gboolean
541 is_valid_data_directory (int i)
543 /*LAMESPEC 4 == certificate 6 == debug, MS uses both*/
544 return i == 1 || i == 2 || i == 5 || i == 12 || i == 14 || i == 4 || i == 6;
547 static void
548 load_data_directories (VerifyContext *ctx)
550 guint32 offset = pe_header_offset (ctx) + 116; /*FIXME, this constant is different under PE32+*/
551 const char *ptr = ctx->data + offset;
552 int i;
554 for (i = 0; i < 16; ++i) {
555 guint32 rva = read32 (ptr);
556 guint32 size = read32 (ptr + 4);
558 /*LAMESPEC the authenticode data directory format is different. We don't support CAS, so lets ignore for now.*/
559 if (i == CERTIFICATE_TABLE_IDX) {
560 ptr += 8;
561 continue;
563 if ((rva != 0 || size != 0) && !is_valid_data_directory (i))
564 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d", i));
566 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
567 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d rva/size pair %x/%x", i, rva, size));
569 ctx->data_directories [i].rva = rva;
570 ctx->data_directories [i].size = size;
571 ctx->data_directories [i].translated_offset = translate_rva (ctx, rva);
573 ptr += 8;
577 #define SIZE_OF_MSCOREE (sizeof ("mscoree.dll"))
579 #define SIZE_OF_CORMAIN (sizeof ("_CorExeMain"))
581 static void
582 verify_hint_name_table (VerifyContext *ctx, guint32 import_rva, const char *table_name)
584 const char *ptr;
585 guint32 hint_table_rva;
587 import_rva = translate_rva (ctx, import_rva);
588 g_assert (import_rva != INVALID_OFFSET);
590 hint_table_rva = read32 (ctx->data + import_rva);
591 if (!bounds_check_virtual_address (ctx, hint_table_rva, SIZE_OF_CORMAIN + 2))
592 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint/Name rva %d for %s", hint_table_rva, table_name));
594 hint_table_rva = translate_rva (ctx, hint_table_rva);
595 g_assert (hint_table_rva != INVALID_OFFSET);
596 ptr = ctx->data + hint_table_rva + 2;
598 if (memcmp ("_CorExeMain", ptr, SIZE_OF_CORMAIN) && memcmp ("_CorDllMain", ptr, SIZE_OF_CORMAIN)) {
599 char name[SIZE_OF_CORMAIN];
600 memcpy (name, ptr, SIZE_OF_CORMAIN);
601 name [SIZE_OF_CORMAIN - 1] = 0;
602 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint / Name: '%s'", name));
606 static void
607 verify_import_table (VerifyContext *ctx)
609 DataDirectory it = ctx->data_directories [IMPORT_TABLE_IDX];
610 guint32 offset = it.translated_offset;
611 const char *ptr = ctx->data + offset;
612 guint32 name_rva, ilt_rva, iat_rva;
614 g_assert (offset != INVALID_OFFSET);
616 if (it.size < 40)
617 ADD_ERROR (ctx, g_strdup_printf ("Import table size %d is smaller than 40", it.size));
619 ilt_rva = read32 (ptr);
620 if (ilt_rva && !bounds_check_virtual_address (ctx, ilt_rva, 8))
621 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Lookup Table rva %x", ilt_rva));
623 name_rva = read32 (ptr + 12);
624 if (name_rva && !bounds_check_virtual_address (ctx, name_rva, SIZE_OF_MSCOREE))
625 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name rva %x", name_rva));
627 iat_rva = read32 (ptr + 16);
628 if (iat_rva) {
629 if (!bounds_check_virtual_address (ctx, iat_rva, 8))
630 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Address Table rva %x", iat_rva));
632 if (iat_rva != ctx->data_directories [IAT_IDX].rva)
633 ADD_ERROR (ctx, g_strdup_printf ("Import Address Table rva %x different from data directory entry %x", read32 (ptr + 16), ctx->data_directories [IAT_IDX].rva));
636 if (name_rva) {
637 name_rva = translate_rva (ctx, name_rva);
638 g_assert (name_rva != INVALID_OFFSET);
639 ptr = ctx->data + name_rva;
641 if (memcmp ("mscoree.dll", ptr, SIZE_OF_MSCOREE)) {
642 char name[SIZE_OF_MSCOREE];
643 memcpy (name, ptr, SIZE_OF_MSCOREE);
644 name [SIZE_OF_MSCOREE - 1] = 0;
645 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name: '%s'", name));
649 if (ilt_rva) {
650 verify_hint_name_table (ctx, ilt_rva, "Import Lookup Table");
651 CHECK_ERROR ();
654 if (iat_rva)
655 verify_hint_name_table (ctx, iat_rva, "Import Address Table");
658 static void
659 verify_resources_table (VerifyContext *ctx)
661 DataDirectory it = ctx->data_directories [RESOURCE_TABLE_IDX];
662 guint32 offset;
663 guint16 named_entries, id_entries;
664 const char *ptr;
666 if (it.rva == 0)
667 return;
669 if (it.size < 16)
670 ADD_ERROR (ctx, g_strdup_printf ("Resource section is too small, must be at least 16 bytes long but it's %d long", it.size));
672 offset = it.translated_offset;
673 ptr = ctx->data + offset;
675 g_assert (offset != INVALID_OFFSET);
677 named_entries = read16 (ptr + 12);
678 id_entries = read16 (ptr + 14);
680 if ((named_entries + id_entries) * 8 + 16 > it.size)
681 ADD_ERROR (ctx, g_strdup_printf ("Resource section is too small, the number of entries (%d) doesn't fit on it's size %d", named_entries + id_entries, it.size));
683 /* XXX at least one unmanaged resource is added due to a call to AssemblyBuilder::DefineVersionInfoResource ()
684 if (named_entries || id_entries)
685 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support full verification of PECOFF resources"));
689 /*----------nothing from here on can use data_directory---*/
691 static DataDirectory
692 get_data_dir (VerifyContext *ctx, int idx)
694 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)ctx->image->image_info;
695 MonoPEDirEntry *entry= &iinfo->cli_header.datadir.pe_export_table;
696 DataDirectory res;
698 entry += idx;
699 res.rva = entry->rva;
700 res.size = entry->size;
701 res.translated_offset = translate_rva (ctx, res.rva);
702 return res;
705 static void
706 verify_cli_header (VerifyContext *ctx)
708 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
709 guint32 offset;
710 const char *ptr;
711 int i;
713 if (it.rva == 0)
714 ADD_ERROR (ctx, g_strdup_printf ("CLI header missing"));
716 if (it.size != 72)
717 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size in data directory %d must be 72", it.size));
719 offset = it.translated_offset;
720 ptr = ctx->data + offset;
722 g_assert (offset != INVALID_OFFSET);
724 if (read16 (ptr) != 72)
725 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size %d must be 72", read16 (ptr)));
727 if (!bounds_check_virtual_address (ctx, read32 (ptr + 8), read32 (ptr + 12)))
728 ADD_ERROR (ctx, g_strdup_printf ("Invalid medatata section rva/size pair %x/%x", read32 (ptr + 8), read32 (ptr + 12)));
731 if (!read32 (ptr + 8) || !read32 (ptr + 12))
732 ADD_ERROR (ctx, g_strdup_printf ("Missing medatata section in the CLI header"));
734 if ((read32 (ptr + 16) & ~0x0003000B) != 0)
735 ADD_ERROR (ctx, g_strdup_printf ("Invalid CLI header flags"));
737 ptr += 24;
738 for (i = 0; i < 6; ++i) {
739 guint32 rva = read32 (ptr);
740 guint32 size = read32 (ptr + 4);
742 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
743 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli section %i rva/size pair %x/%x", i, rva, size));
745 ptr += 8;
747 if (rva && i > 1)
748 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't support cli header section %d", i));
752 static guint32
753 pad4 (guint32 offset)
755 if (offset & 0x3) //pad to the next 4 byte boundary
756 offset = (offset & ~0x3) + 4;
757 return offset;
760 static void
761 verify_metadata_header (VerifyContext *ctx)
763 int i;
764 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
765 guint32 offset, section_count;
766 const char *ptr;
768 offset = it.translated_offset;
769 ptr = ctx->data + offset;
770 g_assert (offset != INVALID_OFFSET);
772 //build a directory entry for the metadata root
773 ptr += 8;
774 it.rva = read32 (ptr);
775 ptr += 4;
776 it.size = read32 (ptr);
777 it.translated_offset = offset = translate_rva (ctx, it.rva);
779 ptr = ctx->data + offset;
780 g_assert (offset != INVALID_OFFSET);
782 if (it.size < 20)
783 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small %d (at least 20 bytes required for initial decoding)", it.size));
785 if (read32 (ptr) != 0x424A5342)
786 ADD_ERROR (ctx, g_strdup_printf ("Invalid metadata signature, expected 0x424A5342 but got %08x", read32 (ptr)));
788 offset = pad4 (offset + 16 + read32 (ptr + 12));
790 if (!bounds_check_datadir (&it, offset, 4))
791 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small %d (at least %d bytes required for flags decoding)", it.size, offset + 4 - it.translated_offset));
793 ptr = ctx->data + offset; //move to streams header
795 section_count = read16 (ptr + 2);
796 if (section_count < 2)
797 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section must have at least 2 streams (#~ and #GUID)"));
799 ptr += 4;
800 offset += 4;
802 for (i = 0; i < section_count; ++i) {
803 guint32 stream_off, stream_size;
804 int string_size, stream_idx;
806 if (!bounds_check_datadir (&it, offset, 8))
807 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small for initial decode of stream header %d, missing %d bytes", i, offset + 9 - it.translated_offset));
809 stream_off = it.translated_offset + read32 (ptr);
810 stream_size = read32 (ptr + 4);
812 if (!bounds_check_datadir (&it, stream_off, stream_size))
813 ADD_ERROR (ctx, g_strdup_printf ("Invalid stream header %d offset/size pair %x/%x", 0, stream_off, stream_size));
815 ptr += 8;
816 offset += 8;
818 for (string_size = 0; string_size < 32; ++string_size) {
819 if (!bounds_check_datadir (&it, offset++, 1))
820 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small to decode stream header %d name", i));
821 if (!ptr [string_size])
822 break;
825 if (ptr [string_size])
826 ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d name larger than 32 bytes", i));
828 if (!strncmp ("#Strings", ptr, 9))
829 stream_idx = STRINGS_STREAM;
830 else if (!strncmp ("#US", ptr, 4))
831 stream_idx = USER_STRINGS_STREAM;
832 else if (!strncmp ("#Blob", ptr, 6))
833 stream_idx = BLOB_STREAM;
834 else if (!strncmp ("#GUID", ptr, 6))
835 stream_idx = GUID_STREAM;
836 else if (!strncmp ("#~", ptr, 3))
837 stream_idx = TILDE_STREAM;
838 else {
839 ADD_WARNING (ctx, g_strdup_printf ("Metadata stream header %d invalid name %s", i, ptr));
840 offset = pad4 (offset);
841 ptr = ctx->data + offset;
842 continue;
845 if (ctx->metadata_streams [stream_idx].offset != 0)
846 ADD_ERROR (ctx, g_strdup_printf ("Duplicated metadata stream header %s", ptr));
848 ctx->metadata_streams [stream_idx].offset = stream_off;
849 ctx->metadata_streams [stream_idx].size = stream_size;
851 offset = pad4 (offset);
852 ptr = ctx->data + offset;
855 if (!ctx->metadata_streams [TILDE_STREAM].size)
856 ADD_ERROR (ctx, g_strdup_printf ("Metadata #~ stream missing"));
857 if (!ctx->metadata_streams [GUID_STREAM].size)
858 ADD_ERROR (ctx, g_strdup_printf ("Metadata guid stream missing"));
861 static void
862 verify_tables_schema (VerifyContext *ctx)
864 OffsetAndSize tables_area = ctx->metadata_streams [TILDE_STREAM];
865 unsigned offset = tables_area.offset;
866 const char *ptr = ctx->data + offset;
867 guint64 valid_tables;
868 guint32 count;
869 int i;
871 if (tables_area.size < 24)
872 ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for initial decoding (requires 24 bytes)", tables_area.size));
874 if (ptr [4] != 2 && ptr [4] != 1)
875 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata major version %d, expected 2", ptr [4]));
876 if (ptr [5] != 0)
877 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata minor version %d, expected 0", ptr [5]));
879 if ((ptr [6] & ~0x7) != 0)
880 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata heap sizes 0x%02x, only bits 0, 1 and 2 can be set", ((unsigned char *) ptr) [6]));
882 valid_tables = read64 (ptr + 8);
883 count = 0;
884 for (i = 0; i < 64; ++i) {
885 if (!(valid_tables & ((guint64)1 << i)))
886 continue;
888 /*MS Extensions: 0x3 0x5 0x7 0x13 0x16
889 Unused: 0x1E 0x1F 0x2D-0x3F
890 We don't care about the MS extensions.*/
891 if (i == 0x3 || i == 0x5 || i == 0x7 || i == 0x13 || i == 0x16)
892 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support MS specific table %x", i));
893 if (i == 0x1E || i == 0x1F || i >= 0x2D)
894 ADD_ERROR (ctx, g_strdup_printf ("Invalid table %x", i));
895 ++count;
898 if (tables_area.size < 24 + count * 4)
899 ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for decoding row counts (requires %d bytes)", tables_area.size, 24 + count * 4));
900 ptr += 24;
902 for (i = 0; i < 64; ++i) {
903 if (valid_tables & ((guint64)1 << i)) {
904 guint32 row_count = read32 (ptr);
905 if (row_count > (1 << 24) - 1)
906 ADD_ERROR (ctx, g_strdup_printf ("Invalid Table %d row count: %d. Mono only supports 16777215 rows", i, row_count));
907 ptr += 4;
912 /*----------nothing from here on can use data_directory or metadata_streams ---*/
914 static guint32
915 get_col_offset (VerifyContext *ctx, int table, int column)
917 guint32 bitfield = ctx->image->tables [table].size_bitfield;
918 guint32 offset = 0;
920 while (column-- > 0)
921 offset += mono_metadata_table_size (bitfield, column);
923 return offset;
926 static guint32
927 get_col_size (VerifyContext *ctx, int table, int column)
929 return mono_metadata_table_size (ctx->image->tables [table].size_bitfield, column);
932 static OffsetAndSize
933 get_metadata_stream (VerifyContext *ctx, MonoStreamHeader *header)
935 OffsetAndSize res;
936 res.offset = header->data - ctx->data;
937 res.size = header->size;
939 return res;
942 static gboolean
943 is_valid_string_full_with_image (MonoImage *image, guint32 offset, gboolean allow_empty)
945 guint32 heap_offset = (char*)image->heap_strings.data - image->raw_data;
946 guint32 heap_size = image->heap_strings.size;
948 glong length;
949 const char *data = image->raw_data + heap_offset;
951 if (offset >= heap_size)
952 return FALSE;
953 if (CHECK_ADDP_OVERFLOW_UN (data, offset))
954 return FALSE;
956 if (!mono_utf8_validate_and_len_with_bounds (data + offset, heap_size - offset, &length, NULL))
957 return FALSE;
958 return allow_empty || length > 0;
962 static gboolean
963 is_valid_string_full (VerifyContext *ctx, guint32 offset, gboolean allow_empty)
965 return is_valid_string_full_with_image (ctx->image, offset, allow_empty);
968 static gboolean
969 is_valid_string (VerifyContext *ctx, guint32 offset)
971 return is_valid_string_full (ctx, offset, TRUE);
974 static gboolean
975 is_valid_non_empty_string (VerifyContext *ctx, guint32 offset)
977 return is_valid_string_full (ctx, offset, FALSE);
980 static gboolean
981 is_valid_guid (VerifyContext *ctx, guint32 offset)
983 OffsetAndSize guids = get_metadata_stream (ctx, &ctx->image->heap_guid);
984 return guids.size >= 8 && guids.size - 8 >= offset;
987 static guint32
988 get_coded_index_token (int token_kind, guint32 coded_token)
990 guint32 bits = coded_index_desc [token_kind];
991 return coded_token >> bits;
994 static guint32
995 get_coded_index_table (int kind, guint32 coded_token)
997 guint32 idx, bits = coded_index_desc [kind];
998 kind += 2;
999 idx = coded_token & ((1 << bits) - 1);
1000 return coded_index_desc [kind + idx];
1003 static guint32
1004 make_coded_token (int kind, guint32 table, guint32 table_idx)
1006 guint32 bits = coded_index_desc [kind++];
1007 guint32 tables = coded_index_desc [kind++];
1008 guint32 i;
1009 for (i = 0; i < tables; ++i) {
1010 if (coded_index_desc [kind++] == table)
1011 return ((table_idx + 1) << bits) | i;
1013 g_assert_not_reached ();
1014 return -1;
1017 static gboolean
1018 is_valid_coded_index_with_image (MonoImage *image, int token_kind, guint32 coded_token)
1020 guint32 bits = coded_index_desc [token_kind++];
1021 guint32 table_count = coded_index_desc [token_kind++];
1022 guint32 table = coded_token & ((1 << bits) - 1);
1023 guint32 token = coded_token >> bits;
1025 if (table >= table_count)
1026 return FALSE;
1028 /*token_kind points to the first table idx*/
1029 table = coded_index_desc [token_kind + table];
1031 if (table == INVALID_TABLE)
1032 return FALSE;
1033 return token <= image->tables [table].rows;
1036 static gboolean
1037 is_valid_coded_index (VerifyContext *ctx, int token_kind, guint32 coded_token)
1039 return is_valid_coded_index_with_image (ctx->image, token_kind, coded_token);
1042 typedef struct {
1043 guint32 token;
1044 guint32 col_size;
1045 guint32 col_offset;
1046 MonoTableInfo *table;
1047 } RowLocator;
1049 static int
1050 token_locator (const void *a, const void *b)
1052 RowLocator *loc = (RowLocator *)a;
1053 unsigned const char *row = (unsigned const char *)b;
1054 guint32 token = loc->col_size == 2 ? read16 (row + loc->col_offset) : read32 (row + loc->col_offset);
1056 VERIFIER_DEBUG ( printf ("\tfound token %x at idx %d\n", token, ((const char*)row - loc->table->base) / loc->table->row_size) );
1057 return (int)loc->token - (int)token;
1060 static int
1061 search_sorted_table (VerifyContext *ctx, int table, int column, guint32 coded_token)
1063 MonoTableInfo *tinfo = &ctx->image->tables [table];
1064 RowLocator locator;
1065 const char *res, *base;
1066 locator.token = coded_token;
1067 locator.col_offset = get_col_offset (ctx, table, column);
1068 locator.col_size = get_col_size (ctx, table, column);
1069 locator.table = tinfo;
1071 base = tinfo->base;
1073 VERIFIER_DEBUG ( printf ("looking token %x table %d col %d rsize %d roff %d\n", coded_token, table, column, locator.col_size, locator.col_offset) );
1074 res = (const char *)mono_binary_search (&locator, base, tinfo->rows, tinfo->row_size, token_locator);
1075 if (!res)
1076 return -1;
1078 return (res - base) / tinfo->row_size;
1081 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1082 static const char*
1083 get_string_ptr (VerifyContext *ctx, guint offset)
1085 return ctx->image->heap_strings.data + offset;
1088 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1089 static int
1090 string_cmp (VerifyContext *ctx, const char *str, guint offset)
1092 if (offset == 0)
1093 return strcmp (str, "");
1095 return strcmp (str, get_string_ptr (ctx, offset));
1098 static gboolean
1099 mono_verifier_is_corlib (MonoImage *image)
1101 gboolean trusted_location = !mono_security_core_clr_enabled () ?
1102 TRUE : mono_security_core_clr_is_platform_image (image);
1104 return trusted_location && image->module_name && !strcmp ("mscorlib.dll", image->module_name);
1107 static gboolean
1108 typedef_is_system_object (VerifyContext *ctx, guint32 *data)
1110 return mono_verifier_is_corlib (ctx->image) && !string_cmp (ctx, "System", data [MONO_TYPEDEF_NAMESPACE]) && !string_cmp (ctx, "Object", data [MONO_TYPEDEF_NAME]);
1113 static gboolean
1114 decode_value (const char *_ptr, unsigned available, unsigned *value, unsigned *size)
1116 unsigned char b;
1117 const unsigned char *ptr = (const unsigned char *)_ptr;
1119 if (!available)
1120 return FALSE;
1122 b = *ptr;
1123 *value = *size = 0;
1125 if ((b & 0x80) == 0) {
1126 *size = 1;
1127 *value = b;
1128 } else if ((b & 0x40) == 0) {
1129 if (available < 2)
1130 return FALSE;
1131 *size = 2;
1132 *value = ((b & 0x3f) << 8 | ptr [1]);
1133 } else {
1134 if (available < 4)
1135 return FALSE;
1136 *size = 4;
1137 *value = ((b & 0x1f) << 24) |
1138 (ptr [1] << 16) |
1139 (ptr [2] << 8) |
1140 ptr [3];
1143 return TRUE;
1146 static gboolean
1147 decode_signature_header (VerifyContext *ctx, guint32 offset, guint32 *size, const char **first_byte)
1149 MonoStreamHeader blob = ctx->image->heap_blob;
1150 guint32 value, enc_size;
1152 if (offset >= blob.size)
1153 return FALSE;
1155 if (!decode_value (blob.data + offset, blob.size - offset, &value, &enc_size))
1156 return FALSE;
1158 if (CHECK_ADD4_OVERFLOW_UN (offset, enc_size))
1159 return FALSE;
1161 offset += enc_size;
1163 if (ADD_IS_GREATER_OR_OVF (offset, value, blob.size))
1164 return FALSE;
1166 *size = value;
1167 *first_byte = blob.data + offset;
1168 return TRUE;
1171 static gboolean
1172 safe_read (const char **_ptr, const char *limit, unsigned *dest, int size)
1174 const char *ptr = *_ptr;
1175 if (ptr + size > limit)
1176 return FALSE;
1177 switch (size) {
1178 case 1:
1179 *dest = *((guint8*)ptr);
1180 ++ptr;
1181 break;
1182 case 2:
1183 *dest = read16 (ptr);
1184 ptr += 2;
1185 break;
1186 case 4:
1187 *dest = read32 (ptr);
1188 ptr += 4;
1189 break;
1191 *_ptr = ptr;
1192 return TRUE;
1195 static gboolean
1196 safe_read_compressed_int (const char **_ptr, const char *limit, unsigned *dest)
1198 unsigned size = 0;
1199 const char *ptr = *_ptr;
1200 gboolean res = decode_value (ptr, limit - ptr, dest, &size);
1201 *_ptr = ptr + size;
1202 return res;
1205 #define safe_read8(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 1)
1206 #define safe_read_cint(VAR, PTR, LIMIT) safe_read_compressed_int (&PTR, LIMIT, &VAR)
1207 #define safe_read16(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 2)
1208 #define safe_read32(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 4)
1210 static gboolean
1211 parse_type (VerifyContext *ctx, const char **_ptr, const char *end);
1213 static gboolean
1214 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged);
1216 static gboolean
1217 parse_custom_mods (VerifyContext *ctx, const char **_ptr, const char *end)
1219 const char *ptr = *_ptr;
1220 unsigned type = 0;
1221 unsigned token = 0;
1223 while (TRUE) {
1224 if (!safe_read8 (type, ptr, end))
1225 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the type"));
1227 if (type != MONO_TYPE_CMOD_REQD && type != MONO_TYPE_CMOD_OPT) {
1228 --ptr;
1229 break;
1232 if (!safe_read_cint (token, ptr, end))
1233 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the token"));
1235 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token) || !get_coded_index_token (TYPEDEF_OR_REF_DESC, token))
1236 FAIL (ctx, g_strdup_printf ("CustomMod: invalid TypeDefOrRef token %x", token));
1239 *_ptr = ptr;
1240 return TRUE;
1243 static gboolean
1244 parse_array_shape (VerifyContext *ctx, const char **_ptr, const char *end)
1246 const char *ptr = *_ptr;
1247 unsigned val = 0;
1248 unsigned size, num, i;
1250 if (!safe_read8 (val, ptr, end))
1251 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for Rank"));
1253 if (val == 0)
1254 FAIL (ctx, g_strdup ("ArrayShape: Invalid shape with zero Rank"));
1256 if (!safe_read_cint (size, ptr, end))
1257 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumSizes"));
1259 for (i = 0; i < size; ++i) {
1260 if (!safe_read_cint (num, ptr, end))
1261 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for Size of rank %d", i + 1));
1264 if (!safe_read_cint (size, ptr, end))
1265 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumLoBounds"));
1267 for (i = 0; i < size; ++i) {
1268 if (!safe_read_cint (num, ptr, end))
1269 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for LoBound of rank %d", i + 1));
1272 *_ptr = ptr;
1273 return TRUE;
1276 static gboolean
1277 parse_generic_inst (VerifyContext *ctx, const char **_ptr, const char *end)
1279 const char *ptr = *_ptr;
1280 unsigned type;
1281 unsigned count, token, i;
1283 if (!safe_read8 (type, ptr, end))
1284 FAIL (ctx, g_strdup ("GenericInst: Not enough room for kind"));
1286 if (type != MONO_TYPE_CLASS && type != MONO_TYPE_VALUETYPE)
1287 FAIL (ctx, g_strdup_printf ("GenericInst: Invalid GenericInst kind %x\n", type));
1289 if (!safe_read_cint (token, ptr, end))
1290 FAIL (ctx, g_strdup ("GenericInst: Not enough room for type token"));
1292 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token) || !get_coded_index_token (TYPEDEF_OR_REF_DESC, token))
1293 FAIL (ctx, g_strdup_printf ("GenericInst: invalid TypeDefOrRef token %x", token));
1295 if (ctx->token) {
1296 if (mono_metadata_token_index (ctx->token) == get_coded_index_token (TYPEDEF_OR_REF_DESC, token) &&
1297 mono_metadata_token_table (ctx->token) == get_coded_index_table (TYPEDEF_OR_REF_DESC, token))
1298 FAIL (ctx, g_strdup_printf ("Type: Recurside generic instance specification (%x). A type signature can't reference itself", ctx->token));
1301 if (!safe_read_cint (count, ptr, end))
1302 FAIL (ctx, g_strdup ("GenericInst: Not enough room for argument count"));
1304 if (count == 0)
1305 FAIL (ctx, g_strdup ("GenericInst: Zero arguments generic instance"));
1307 for (i = 0; i < count; ++i) {
1308 if (!parse_custom_mods (ctx, &ptr, end))
1309 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1311 if (!parse_type (ctx, &ptr, end))
1312 FAIL (ctx, g_strdup_printf ("GenericInst: invalid generic argument %d", i + 1));
1314 *_ptr = ptr;
1315 return TRUE;
1318 static gboolean
1319 parse_type (VerifyContext *ctx, const char **_ptr, const char *end)
1321 const char *ptr = *_ptr;
1322 unsigned type;
1323 unsigned token = 0;
1325 if (!safe_read8 (type, ptr, end))
1326 FAIL (ctx, g_strdup ("Type: Not enough room for the type"));
1328 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_PTR) ||
1329 (type >= MONO_TYPE_VALUETYPE && type <= MONO_TYPE_GENERICINST) ||
1330 (type >= MONO_TYPE_I && type <= MONO_TYPE_U) ||
1331 (type >= MONO_TYPE_FNPTR && type <= MONO_TYPE_MVAR)))
1332 FAIL (ctx, g_strdup_printf ("Type: Invalid type kind %x\n", type));
1334 switch (type) {
1335 case MONO_TYPE_PTR:
1336 if (!parse_custom_mods (ctx, &ptr, end))
1337 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1339 if (!safe_read8 (type, ptr, end))
1340 FAIL (ctx, g_strdup ("Type: Not enough room to parse the pointer type"));
1342 if (type != MONO_TYPE_VOID) {
1343 --ptr;
1344 if (!parse_type (ctx, &ptr, end))
1345 FAIL (ctx, g_strdup ("Type: Could not parse pointer type"));
1347 break;
1349 case MONO_TYPE_VALUETYPE:
1350 case MONO_TYPE_CLASS:
1351 if (!safe_read_cint (token, ptr, end))
1352 FAIL (ctx, g_strdup ("Type: Not enough room for the type token"));
1354 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token) || !get_coded_index_token (TYPEDEF_OR_REF_DESC, token))
1355 FAIL (ctx, g_strdup_printf ("Type: invalid TypeDefOrRef token %x", token));
1357 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, token))
1358 FAIL (ctx, g_strdup_printf ("Type: zero TypeDefOrRef token %x", token));
1359 if (ctx->token) {
1360 if (mono_metadata_token_index (ctx->token) == get_coded_index_token (TYPEDEF_OR_REF_DESC, token) &&
1361 mono_metadata_token_table (ctx->token) == get_coded_index_table (TYPEDEF_OR_REF_DESC, token))
1362 FAIL (ctx, g_strdup_printf ("Type: Recursive type specification (%x). A type signature can't reference itself", ctx->token));
1364 break;
1366 case MONO_TYPE_VAR:
1367 case MONO_TYPE_MVAR:
1368 if (!safe_read_cint (token, ptr, end))
1369 FAIL (ctx, g_strdup ("Type: Not enough room for to decode generic argument number"));
1370 break;
1372 case MONO_TYPE_ARRAY:
1373 if (!parse_type (ctx, &ptr, end))
1374 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1375 if (!parse_array_shape (ctx, &ptr, end))
1376 FAIL (ctx, g_strdup ("Type: Could not parse array shape"));
1377 break;
1379 case MONO_TYPE_GENERICINST:
1380 if (!parse_generic_inst (ctx, &ptr, end))
1381 FAIL (ctx, g_strdup ("Type: Could not parse generic inst"));
1382 break;
1384 case MONO_TYPE_FNPTR:
1385 if (!parse_method_signature (ctx, &ptr, end, TRUE, TRUE))
1386 FAIL (ctx, g_strdup ("Type: Could not parse method pointer signature"));
1387 break;
1389 case MONO_TYPE_SZARRAY:
1390 if (!parse_custom_mods (ctx, &ptr, end))
1391 FAIL (ctx, g_strdup ("Type: Failed to parse array element custom attr"));
1392 if (!parse_type (ctx, &ptr, end))
1393 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1394 break;
1396 *_ptr = ptr;
1397 return TRUE;
1400 static gboolean
1401 parse_return_type (VerifyContext *ctx, const char **_ptr, const char *end)
1403 const char *ptr;
1404 unsigned type = 0;
1406 if (!parse_custom_mods (ctx, _ptr, end))
1407 return FALSE;
1409 ptr = *_ptr;
1410 if (!safe_read8 (type, ptr, end))
1411 FAIL (ctx, g_strdup ("ReturnType: Not enough room for the type"));
1413 if (type == MONO_TYPE_VOID || type == MONO_TYPE_TYPEDBYREF) {
1414 *_ptr = ptr;
1415 return TRUE;
1418 //it's a byref, update the cursor ptr
1419 if (type == MONO_TYPE_BYREF)
1420 *_ptr = ptr;
1422 return parse_type (ctx, _ptr, end);
1425 static gboolean
1426 parse_param (VerifyContext *ctx, const char **_ptr, const char *end)
1428 const char *ptr;
1429 unsigned type = 0;
1431 if (!parse_custom_mods (ctx, _ptr, end))
1432 return FALSE;
1434 ptr = *_ptr;
1435 if (!safe_read8 (type, ptr, end))
1436 FAIL (ctx, g_strdup ("Param: Not enough room for the type"));
1438 if (type == MONO_TYPE_TYPEDBYREF) {
1439 *_ptr = ptr;
1440 return TRUE;
1443 //it's a byref, update the cursor ptr
1444 if (type == MONO_TYPE_BYREF) {
1445 *_ptr = ptr;
1446 if (!parse_custom_mods (ctx, _ptr, end))
1447 return FALSE;
1450 return parse_type (ctx, _ptr, end);
1453 static gboolean
1454 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged)
1456 unsigned cconv = 0;
1457 unsigned param_count = 0, gparam_count = 0, type = 0, i;
1458 const char *ptr = *_ptr;
1459 gboolean saw_sentinel = FALSE;
1461 if (!safe_read8 (cconv, ptr, end))
1462 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the call conv"));
1464 if (cconv & 0x80)
1465 FAIL (ctx, g_strdup ("MethodSig: CallConv has 0x80 set"));
1467 if (allow_unmanaged) {
1468 if ((cconv & 0x0F) > MONO_CALL_VARARG)
1469 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not valid, it's %x", cconv & 0x0F));
1470 } else if ((cconv & 0x0F) != MONO_CALL_DEFAULT && (cconv & 0x0F) != MONO_CALL_VARARG)
1471 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not Default or Vararg, it's %x", cconv & 0x0F));
1473 if ((cconv & 0x10) && !safe_read_cint (gparam_count, ptr, end))
1474 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the generic param count"));
1476 if ((cconv & 0x10) && gparam_count == 0)
1477 FAIL (ctx, g_strdup ("MethodSig: Signature with generics but zero arity"));
1479 if (allow_unmanaged && (cconv & 0x10))
1480 FAIL (ctx, g_strdup ("MethodSig: Standalone signature with generic params"));
1482 if (!safe_read_cint (param_count, ptr, end))
1483 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the param count"));
1485 if (!parse_return_type (ctx, &ptr, end))
1486 FAIL (ctx, g_strdup ("MethodSig: Error parsing return type"));
1488 for (i = 0; i < param_count; ++i) {
1489 if (allow_sentinel) {
1490 if (!safe_read8 (type, ptr, end))
1491 FAIL (ctx, g_strdup_printf ("MethodSig: Not enough room for param %d type", i));
1493 if (type == MONO_TYPE_SENTINEL) {
1494 if ((cconv & 0x0F) != MONO_CALL_VARARG)
1495 FAIL (ctx, g_strdup ("MethodSig: Found sentinel but signature is not vararg"));
1497 if (saw_sentinel)
1498 FAIL (ctx, g_strdup ("MethodSig: More than one sentinel type"));
1500 saw_sentinel = TRUE;
1501 } else {
1502 --ptr;
1506 if (!parse_param (ctx, &ptr, end))
1507 FAIL (ctx, g_strdup_printf ("MethodSig: Error parsing arg %d", i));
1510 *_ptr = ptr;
1511 return TRUE;
1514 static gboolean
1515 parse_property_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1517 unsigned type = 0;
1518 unsigned sig = 0;
1519 unsigned param_count = 0, i;
1520 const char *ptr = *_ptr;
1522 if (!safe_read8 (sig, ptr, end))
1523 FAIL (ctx, g_strdup ("PropertySig: Not enough room for signature"));
1525 if (sig != 0x08 && sig != 0x28)
1526 FAIL (ctx, g_strdup_printf ("PropertySig: Signature is not 0x28 or 0x08: %x", sig));
1528 if (!safe_read_cint (param_count, ptr, end))
1529 FAIL (ctx, g_strdup ("PropertySig: Not enough room for the param count"));
1531 if (!parse_custom_mods (ctx, &ptr, end))
1532 return FALSE;
1534 if (!safe_read8 (type, ptr, end))
1535 FAIL (ctx, g_strdup ("PropertySig: Not enough room for the type"));
1537 //check if it's a byref. safe_read8 did update ptr, so we rollback if it's not a byref
1538 if (type != MONO_TYPE_BYREF)
1539 --ptr;
1541 if (!parse_type (ctx, &ptr, end))
1542 FAIL (ctx, g_strdup ("PropertySig: Could not parse property type"));
1544 for (i = 0; i < param_count; ++i) {
1545 if (!parse_custom_mods (ctx, &ptr, end))
1546 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1547 if (!parse_type (ctx, &ptr, end))
1548 FAIL (ctx, g_strdup_printf ("PropertySig: Error parsing arg %d", i));
1551 *_ptr = ptr;
1552 return TRUE;
1555 static gboolean
1556 parse_field (VerifyContext *ctx, const char **_ptr, const char *end)
1558 const char *ptr = *_ptr;
1559 unsigned signature = 0;
1561 if (!safe_read8 (signature, ptr, end))
1562 FAIL (ctx, g_strdup ("Field: Not enough room for field signature"));
1564 if (signature != 0x06)
1565 FAIL (ctx, g_strdup_printf ("Field: Invalid signature 0x%x, must be 6", signature));
1567 if (!parse_custom_mods (ctx, &ptr, end))
1568 return FALSE;
1570 if (safe_read8 (signature, ptr, end)) {
1571 if (signature != MONO_TYPE_BYREF)
1572 --ptr;
1574 *_ptr = ptr;
1576 return parse_type (ctx, _ptr, end);
1579 static gboolean
1580 parse_locals_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1582 unsigned sig = 0;
1583 unsigned locals_count = 0, i;
1584 const char *ptr = *_ptr;
1586 if (!safe_read8 (sig, ptr, end))
1587 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for signature"));
1589 if (sig != 0x07)
1590 FAIL (ctx, g_strdup_printf ("LocalsSig: Signature is not 0x28 or 0x08: %x", sig));
1592 if (!safe_read_cint (locals_count, ptr, end))
1593 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for the param count"));
1595 /* LAMEIMPL: MS sometimes generates empty local signatures and its verifier is ok with.
1596 if (locals_count == 0)
1597 FAIL (ctx, g_strdup ("LocalsSig: Signature with zero locals"));
1600 for (i = 0; i < locals_count; ++i) {
1601 if (!safe_read8 (sig, ptr, end))
1602 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1604 while (sig == MONO_TYPE_CMOD_REQD || sig == MONO_TYPE_CMOD_OPT || sig == MONO_TYPE_PINNED) {
1605 if (sig != MONO_TYPE_PINNED && !parse_custom_mods (ctx, &ptr, end))
1606 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1607 if (!safe_read8 (sig, ptr, end))
1608 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1611 if (sig == MONO_TYPE_BYREF) {
1612 if (!safe_read8 (sig, ptr, end))
1613 FAIL (ctx, g_strdup_printf ("Type: Not enough room for byref type for local %d", i));
1614 if (sig == MONO_TYPE_TYPEDBYREF)
1615 FAIL (ctx, g_strdup_printf ("Type: Invalid type typedref& for local %d", i));
1618 if (sig == MONO_TYPE_TYPEDBYREF)
1619 continue;
1621 --ptr;
1623 if (!parse_type (ctx, &ptr, end))
1624 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1627 *_ptr = ptr;
1628 return TRUE;
1631 static gboolean
1632 is_valid_field_signature (VerifyContext *ctx, guint32 offset)
1634 guint32 size = 0;
1635 unsigned signature = 0;
1636 const char *ptr = NULL, *end;
1638 if (!decode_signature_header (ctx, offset, &size, &ptr))
1639 FAIL (ctx, g_strdup ("FieldSig: Could not decode signature header"));
1640 end = ptr + size;
1642 if (!safe_read8 (signature, ptr, end))
1643 FAIL (ctx, g_strdup ("FieldSig: Not enough room for the signature"));
1645 if (signature != 6)
1646 FAIL (ctx, g_strdup_printf ("FieldSig: Invalid signature %x", signature));
1647 --ptr;
1649 return parse_field (ctx, &ptr, end);
1652 static gboolean
1653 is_valid_method_signature (VerifyContext *ctx, guint32 offset)
1655 guint32 size = 0;
1656 const char *ptr = NULL, *end;
1658 if (!decode_signature_header (ctx, offset, &size, &ptr))
1659 FAIL (ctx, g_strdup ("MethodSig: Could not decode signature header"));
1660 end = ptr + size;
1662 return parse_method_signature (ctx, &ptr, end, FALSE, FALSE);
1665 static gboolean
1666 is_valid_memberref_method_signature (VerifyContext *ctx, guint32 offset)
1668 guint32 size = 0;
1669 const char *ptr = NULL, *end;
1671 if (!decode_signature_header (ctx, offset, &size, &ptr))
1672 FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
1673 end = ptr + size;
1675 return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1679 static gboolean
1680 is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
1682 guint32 size = 0;
1683 unsigned signature = 0;
1684 const char *ptr = NULL, *end;
1686 if (!decode_signature_header (ctx, offset, &size, &ptr))
1687 FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
1688 end = ptr + size;
1690 if (!safe_read8 (signature, ptr, end))
1691 FAIL (ctx, g_strdup ("MemberRefSig: Not enough room for the call conv"));
1692 --ptr;
1694 if (signature == 0x06)
1695 return parse_field (ctx, &ptr, end);
1697 return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1700 static gboolean
1701 is_valid_cattr_blob (VerifyContext *ctx, guint32 offset)
1703 guint32 size = 0;
1704 unsigned prolog = 0;
1705 const char *ptr = NULL, *end;
1707 if (!offset)
1708 return TRUE;
1710 if (!decode_signature_header (ctx, offset, &size, &ptr))
1711 FAIL (ctx, g_strdup ("CustomAttribute: Could not decode signature header"));
1712 end = ptr + size;
1714 if (!safe_read16 (prolog, ptr, end))
1715 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1717 if (prolog != 1)
1718 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1720 return TRUE;
1723 static gboolean
1724 is_valid_cattr_type (MonoType *type)
1726 MonoClass *klass;
1728 if (type->type == MONO_TYPE_OBJECT || (type->type >= MONO_TYPE_BOOLEAN && type->type <= MONO_TYPE_STRING))
1729 return TRUE;
1731 if (type->type == MONO_TYPE_VALUETYPE) {
1732 klass = mono_class_from_mono_type (type);
1733 return klass && klass->enumtype;
1736 if (type->type == MONO_TYPE_CLASS)
1737 return mono_class_from_mono_type (type) == mono_defaults.systemtype_class;
1739 return FALSE;
1742 static gboolean
1743 is_valid_ser_string_full (VerifyContext *ctx, const char **str_start, guint32 *str_len, const char **_ptr, const char *end)
1745 guint32 size = 0;
1746 const char *ptr = *_ptr;
1748 *str_start = NULL;
1749 *str_len = 0;
1751 if (ptr >= end)
1752 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string size"));
1754 /*NULL string*/
1755 if (*ptr == (char)0xFF) {
1756 *_ptr = ptr + 1;
1757 return TRUE;
1760 if (!safe_read_cint (size, ptr, end))
1761 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string size"));
1763 if (ADDP_IS_GREATER_OR_OVF (ptr, size, end))
1764 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string"));
1766 *str_start = ptr;
1767 *str_len = size;
1769 *_ptr = ptr + size;
1770 return TRUE;
1773 static gboolean
1774 is_valid_ser_string (VerifyContext *ctx, const char **_ptr, const char *end)
1776 const char *dummy_str;
1777 guint32 dummy_int;
1778 return is_valid_ser_string_full (ctx, &dummy_str, &dummy_int, _ptr, end);
1781 static MonoClass*
1782 get_enum_by_encoded_name (VerifyContext *ctx, const char **_ptr, const char *end)
1784 MonoType *type;
1785 MonoClass *klass;
1786 const char *str_start = NULL;
1787 const char *ptr = *_ptr;
1788 char *enum_name;
1789 guint32 str_len = 0;
1791 if (!is_valid_ser_string_full (ctx, &str_start, &str_len, &ptr, end))
1792 return NULL;
1794 /*NULL or empty string*/
1795 if (str_start == NULL || str_len == 0) {
1796 ADD_ERROR_NO_RETURN (ctx, g_strdup ("CustomAttribute: Null or empty enum name"));
1797 return NULL;
1800 enum_name = (char *)g_memdup (str_start, str_len + 1);
1801 enum_name [str_len] = 0;
1802 type = mono_reflection_type_from_name (enum_name, ctx->image);
1803 if (!type) {
1804 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute: Invalid enum class %s", enum_name));
1805 g_free (enum_name);
1806 return NULL;
1808 g_free (enum_name);
1810 klass = mono_class_from_mono_type (type);
1811 if (!klass || !klass->enumtype) {
1812 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute:Class %s::%s is not an enum", klass->name_space, klass->name));
1813 return NULL;
1816 *_ptr = ptr;
1817 return klass;
1820 static gboolean
1821 is_valid_fixed_param (VerifyContext *ctx, MonoType *mono_type, const char **_ptr, const char *end)
1823 MonoClass *klass;
1824 const char *ptr = *_ptr;
1825 int elem_size = 0;
1826 guint32 element_count, i;
1827 int type;
1829 klass = mono_type->data.klass;
1830 type = mono_type->type;
1832 handle_enum:
1833 switch (type) {
1834 case MONO_TYPE_BOOLEAN:
1835 case MONO_TYPE_I1:
1836 case MONO_TYPE_U1:
1837 elem_size = 1;
1838 break;
1839 case MONO_TYPE_I2:
1840 case MONO_TYPE_U2:
1841 case MONO_TYPE_CHAR:
1842 elem_size = 2;
1843 break;
1844 case MONO_TYPE_I4:
1845 case MONO_TYPE_U4:
1846 case MONO_TYPE_R4:
1847 elem_size = 4;
1848 break;
1849 case MONO_TYPE_I8:
1850 case MONO_TYPE_U8:
1851 case MONO_TYPE_R8:
1852 elem_size = 8;
1853 break;
1855 case MONO_TYPE_STRING:
1856 *_ptr = ptr;
1857 return is_valid_ser_string (ctx, _ptr, end);
1859 case MONO_TYPE_OBJECT: {
1860 unsigned sub_type = 0;
1861 if (!safe_read8 (sub_type, ptr, end))
1862 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array type"));
1864 if (sub_type >= MONO_TYPE_BOOLEAN && sub_type <= MONO_TYPE_STRING) {
1865 type = sub_type;
1866 goto handle_enum;
1868 if (sub_type == MONO_TYPE_ENUM) {
1869 klass = get_enum_by_encoded_name (ctx, &ptr, end);
1870 if (!klass)
1871 return FALSE;
1873 klass = klass->element_class;
1874 type = klass->byval_arg.type;
1875 goto handle_enum;
1877 if (sub_type == 0x50) { /*Type*/
1878 *_ptr = ptr;
1879 return is_valid_ser_string (ctx, _ptr, end);
1881 if (sub_type == MONO_TYPE_SZARRAY) {
1882 MonoType simple_type = {{0}};
1883 unsigned etype = 0;
1884 if (!safe_read8 (etype, ptr, end))
1885 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array element type"));
1887 if (etype == MONO_TYPE_ENUM) {
1888 klass = get_enum_by_encoded_name (ctx, &ptr, end);
1889 if (!klass)
1890 return FALSE;
1891 } else if (etype == 0x50 || etype == MONO_TYPE_CLASS) {
1892 klass = mono_defaults.systemtype_class;
1893 } else if ((etype >= MONO_TYPE_BOOLEAN && etype <= MONO_TYPE_STRING) || etype == 0x51) {
1894 simple_type.type = etype == 0x51 ? MONO_TYPE_OBJECT : (MonoTypeEnum)etype;
1895 klass = mono_class_from_mono_type (&simple_type);
1896 } else
1897 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype));
1899 type = MONO_TYPE_SZARRAY;
1900 goto handle_enum;
1902 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid boxed object type %x", sub_type));
1905 case MONO_TYPE_CLASS:
1906 if (klass && klass->enumtype) {
1907 klass = klass->element_class;
1908 type = klass->byval_arg.type;
1909 goto handle_enum;
1912 if (klass != mono_defaults.systemtype_class)
1913 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid class parameter type %s:%s ",klass->name_space, klass->name));
1914 *_ptr = ptr;
1915 return is_valid_ser_string (ctx, _ptr, end);
1917 case MONO_TYPE_VALUETYPE:
1918 if (!klass || !klass->enumtype)
1919 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid valuetype parameter expected enum %s:%s ",klass->name_space, klass->name));
1921 klass = klass->element_class;
1922 type = klass->byval_arg.type;
1923 goto handle_enum;
1925 case MONO_TYPE_SZARRAY:
1926 mono_type = &klass->byval_arg;
1927 if (!is_valid_cattr_type (mono_type))
1928 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %s:%s ",klass->name_space, klass->name));
1929 if (!safe_read32 (element_count, ptr, end))
1930 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid class parameter type %s:%s ",klass->name_space, klass->name));
1931 if (element_count == 0xFFFFFFFFu) {
1932 *_ptr = ptr;
1933 return TRUE;
1935 for (i = 0; i < element_count; ++i) {
1936 if (!is_valid_fixed_param (ctx, mono_type, &ptr, end))
1937 return FALSE;
1939 *_ptr = ptr;
1940 return TRUE;
1941 default:
1942 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid parameter type %x ", type));
1945 if (ADDP_IS_GREATER_OR_OVF (ptr, elem_size, end))
1946 FAIL (ctx, g_strdup ("CustomAttribute: Not enough space for element"));
1947 *_ptr = ptr + elem_size;
1948 return TRUE;
1951 static gboolean
1952 is_valid_cattr_content (VerifyContext *ctx, MonoMethod *ctor, const char *ptr, guint32 size)
1954 MonoError error;
1955 unsigned prolog = 0;
1956 const char *end;
1957 MonoMethodSignature *sig;
1958 int args, i;
1959 unsigned num_named;
1961 if (!ctor)
1962 FAIL (ctx, g_strdup ("CustomAttribute: Invalid constructor"));
1964 sig = mono_method_signature_checked (ctor, &error);
1965 if (!mono_error_ok (&error)) {
1966 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute: Invalid constructor signature %s", mono_error_get_message (&error)));
1967 mono_error_cleanup (&error);
1968 return FALSE;
1971 if (sig->sentinelpos != -1 || sig->call_convention == MONO_CALL_VARARG)
1972 FAIL (ctx, g_strdup ("CustomAttribute: Constructor cannot have VARAG signature"));
1974 end = ptr + size;
1976 if (!safe_read16 (prolog, ptr, end))
1977 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1979 if (prolog != 1)
1980 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1982 args = sig->param_count;
1983 for (i = 0; i < args; ++i) {
1984 MonoType *arg_type = sig->params [i];
1985 if (!is_valid_fixed_param (ctx, arg_type, &ptr, end))
1986 return FALSE;
1989 if (!safe_read16 (num_named, ptr, end))
1990 FAIL (ctx, g_strdup ("CustomAttribute: Not enough space for num_named field"));
1992 for (i = 0; i < num_named; ++i) {
1993 MonoType *type, simple_type = {{0}};
1994 unsigned kind;
1996 if (!safe_read8 (kind, ptr, end))
1997 FAIL (ctx, g_strdup_printf ("CustomAttribute: Not enough space for named parameter %d kind", i));
1998 if (kind != 0x53 && kind != 0x54)
1999 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid named parameter %d kind %x", i, kind));
2000 if (!safe_read8 (kind, ptr, end))
2001 FAIL (ctx, g_strdup_printf ("CustomAttribute: Not enough space for named parameter %d type", i));
2003 if (kind >= MONO_TYPE_BOOLEAN && kind <= MONO_TYPE_STRING) {
2004 simple_type.type = (MonoTypeEnum)kind;
2005 type = &simple_type;
2006 } else if (kind == MONO_TYPE_ENUM) {
2007 MonoClass *klass = get_enum_by_encoded_name (ctx, &ptr, end);
2008 if (!klass)
2009 return FALSE;
2010 type = &klass->byval_arg;
2011 } else if (kind == 0x50) {
2012 type = &mono_defaults.systemtype_class->byval_arg;
2013 } else if (kind == 0x51) {
2014 type = &mono_defaults.object_class->byval_arg;
2015 } else if (kind == MONO_TYPE_SZARRAY) {
2016 MonoClass *klass;
2017 unsigned etype = 0;
2018 if (!safe_read8 (etype, ptr, end))
2019 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array element type"));
2021 if (etype == MONO_TYPE_ENUM) {
2022 klass = get_enum_by_encoded_name (ctx, &ptr, end);
2023 if (!klass)
2024 return FALSE;
2025 } else if (etype == 0x50 || etype == MONO_TYPE_CLASS) {
2026 klass = mono_defaults.systemtype_class;
2027 } else if ((etype >= MONO_TYPE_BOOLEAN && etype <= MONO_TYPE_STRING) || etype == 0x51) {
2028 simple_type.type = etype == 0x51 ? MONO_TYPE_OBJECT : (MonoTypeEnum)etype;
2029 klass = mono_class_from_mono_type (&simple_type);
2030 } else
2031 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype));
2033 type = &mono_array_class_get (klass, 1)->byval_arg;
2034 } else {
2035 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid named parameter type %x", kind));
2038 if (!is_valid_ser_string (ctx, &ptr, end))
2039 return FALSE;
2041 if (!is_valid_fixed_param (ctx, type, &ptr, end))
2042 return FALSE;
2046 return TRUE;
2049 static gboolean
2050 is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
2052 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2053 //TODO do proper verification
2054 return blob.size >= 1 && blob.size - 1 >= offset;
2057 static gboolean
2058 is_valid_permission_set (VerifyContext *ctx, guint32 offset)
2060 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2061 //TODO do proper verification
2062 return blob.size >= 1 && blob.size - 1 >= offset;
2065 static gboolean
2066 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
2068 guint32 size = 0;
2069 unsigned signature = 0;
2070 const char *ptr = NULL, *end;
2072 if (!decode_signature_header (ctx, offset, &size, &ptr))
2073 FAIL (ctx, g_strdup ("StandAloneSig: Could not decode signature header"));
2074 end = ptr + size;
2076 if (!safe_read8 (signature, ptr, end))
2077 FAIL (ctx, g_strdup ("StandAloneSig: Not enough room for the call conv"));
2079 --ptr;
2080 if (signature == 0x07)
2081 return parse_locals_signature (ctx, &ptr, end);
2083 /*F# and managed C++ produce standalonesig for fields even thou the spec doesn't mention it.*/
2084 if (signature == 0x06)
2085 return parse_field (ctx, &ptr, end);
2087 return parse_method_signature (ctx, &ptr, end, TRUE, TRUE);
2090 static gboolean
2091 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
2093 guint32 size = 0;
2094 const char *ptr = NULL, *end;
2096 if (!decode_signature_header (ctx, offset, &size, &ptr))
2097 FAIL (ctx, g_strdup ("PropertySig: Could not decode signature header"));
2098 end = ptr + size;
2100 return parse_property_signature (ctx, &ptr, end);
2103 static gboolean
2104 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
2106 guint32 size = 0;
2107 const char *ptr = NULL, *end;
2108 unsigned type = 0;
2110 if (!decode_signature_header (ctx, offset, &size, &ptr))
2111 FAIL (ctx, g_strdup ("TypeSpec: Could not decode signature header"));
2112 end = ptr + size;
2114 if (!parse_custom_mods (ctx, &ptr, end))
2115 return FALSE;
2117 if (!safe_read8 (type, ptr, end))
2118 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for type"));
2120 if (type == MONO_TYPE_BYREF) {
2121 if (!safe_read8 (type, ptr, end))
2122 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for byref type"));
2123 if (type == MONO_TYPE_TYPEDBYREF)
2124 FAIL (ctx, g_strdup ("TypeSpec: Invalid type typedref&"));
2127 if (type == MONO_TYPE_TYPEDBYREF)
2128 return TRUE;
2130 --ptr;
2131 return parse_type (ctx, &ptr, end);
2134 static gboolean
2135 is_valid_methodspec_blob (VerifyContext *ctx, guint32 offset)
2137 guint32 size = 0;
2138 const char *ptr = NULL, *end;
2139 unsigned type = 0;
2140 unsigned count = 0, i;
2142 if (!decode_signature_header (ctx, offset, &size, &ptr))
2143 FAIL (ctx, g_strdup ("MethodSpec: Could not decode signature header"));
2144 end = ptr + size;
2146 if (!safe_read8 (type, ptr, end))
2147 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for call convention"));
2149 if (type != 0x0A)
2150 FAIL (ctx, g_strdup_printf ("MethodSpec: Invalid call convention 0x%x, expected 0x0A", type));
2152 if (!safe_read_cint (count, ptr, end))
2153 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for parameter count"));
2155 if (!count)
2156 FAIL (ctx, g_strdup ("MethodSpec: Zero generic argument count"));
2158 for (i = 0; i < count; ++i) {
2159 if (!parse_custom_mods (ctx, &ptr, end))
2160 return FALSE;
2161 if (!parse_type (ctx, &ptr, end))
2162 FAIL (ctx, g_strdup_printf ("MethodSpec: Could not parse parameter %d", i + 1));
2164 return TRUE;
2167 static gboolean
2168 is_valid_blob_object (VerifyContext *ctx, guint32 offset, guint32 minsize)
2170 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2171 guint32 entry_size, bytes;
2173 if (blob.size < offset)
2174 return FALSE;
2176 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
2177 return FALSE;
2179 if (entry_size < minsize)
2180 return FALSE;
2182 if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
2183 return FALSE;
2184 entry_size += bytes;
2186 return !ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size);
2189 static gboolean
2190 is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
2192 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2193 guint32 size, entry_size, bytes;
2195 if (blob.size < offset)
2196 FAIL (ctx, g_strdup ("ContantValue: invalid offset"));
2198 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
2199 FAIL (ctx, g_strdup ("ContantValue: not enough space to decode size"));
2201 if (type == MONO_TYPE_STRING) {
2202 //String is encoded as: compressed_int:len len *bytes
2203 offset += bytes;
2205 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size))
2206 FAIL (ctx, g_strdup_printf ("ContantValue: not enough space for string, required %d but got %d", entry_size * 2, blob.size - offset));
2208 return TRUE;
2211 switch (type) {
2212 case MONO_TYPE_BOOLEAN:
2213 case MONO_TYPE_I1:
2214 case MONO_TYPE_U1:
2215 size = 1;
2216 break;
2217 case MONO_TYPE_CHAR:
2218 case MONO_TYPE_I2:
2219 case MONO_TYPE_U2:
2220 size = 2;
2221 break;
2222 case MONO_TYPE_I4:
2223 case MONO_TYPE_U4:
2224 case MONO_TYPE_R4:
2225 case MONO_TYPE_CLASS:
2226 size = 4;
2227 break;
2229 case MONO_TYPE_I8:
2230 case MONO_TYPE_U8:
2231 case MONO_TYPE_R8:
2232 size = 8;
2233 break;
2234 default:
2235 g_assert_not_reached ();
2238 if (size != entry_size)
2239 FAIL (ctx, g_strdup_printf ("ContantValue: Expected size %d but got %d", size, entry_size));
2241 offset += bytes;
2243 if (ADD_IS_GREATER_OR_OVF (offset, size, blob.size))
2244 FAIL (ctx, g_strdup_printf ("ContantValue: Not enough room for constant, required %d but have %d", size, blob.size - offset));
2246 if (type == MONO_TYPE_CLASS && read32 (ctx->data + blob.offset + offset))
2247 FAIL (ctx, g_strdup_printf ("ContantValue: Type is class but value is not null"));
2248 return TRUE;
2251 #define FAT_HEADER_INVALID_FLAGS ~(0x3 | 0x8 | 0x10 | 0xF000)
2252 //only 0x01, 0x40 and 0x80 are allowed
2253 #define SECTION_HEADER_INVALID_FLAGS 0x3E
2255 static gboolean
2256 is_valid_method_header (VerifyContext *ctx, guint32 rva, guint32 *locals_token)
2258 unsigned local_vars_tok, code_size, offset = mono_cli_rva_image_map (ctx->image, rva);
2259 unsigned header = 0;
2260 unsigned fat_header = 0, size = 0, max_stack;
2261 const char *ptr = NULL, *end;
2263 *locals_token = 0;
2265 if (offset == INVALID_ADDRESS)
2266 FAIL (ctx, g_strdup ("MethodHeader: Invalid RVA"));
2268 ptr = ctx->data + offset;
2269 end = ctx->data + ctx->size; /*no worries if it spawns multiple sections*/
2271 if (!safe_read8 (header, ptr, end))
2272 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for header"));
2274 switch (header & 0x3) {
2275 case 0:
2276 case 1:
2277 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid header type 0x%x", header & 0x3));
2278 case 2:
2279 header >>= 2;
2280 if (ADDP_IS_GREATER_OR_OVF (ptr, header, end))
2281 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for method body. Required %d, but only %d is available", header, (int)(end - ptr)));
2282 return TRUE;
2284 //FAT HEADER
2285 --ptr;
2286 if (!safe_read16 (fat_header, ptr, end))
2287 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for fat header"));
2289 size = (fat_header >> 12) & 0xF;
2290 if (size != 3)
2291 FAIL (ctx, g_strdup ("MethodHeader: header size must be 3"));
2293 if (!safe_read16 (max_stack, ptr, end))
2294 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for max stack"));
2296 if (!safe_read32 (code_size, ptr, end))
2297 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for code size"));
2299 if (!safe_read32 (local_vars_tok, ptr, end))
2300 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for local vars tok"));
2302 if (local_vars_tok) {
2303 if (((local_vars_tok >> 24) & 0xFF) != 0x11)
2304 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature table 0x%x", ((local_vars_tok >> 24) & 0xFF)));
2305 if ((local_vars_tok & 0xFFFFFF) > ctx->image->tables [MONO_TABLE_STANDALONESIG].rows)
2306 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature points to invalid row 0x%x", local_vars_tok & 0xFFFFFF));
2307 if (!(local_vars_tok & 0xFFFFFF))
2308 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature with zero index"));
2309 *locals_token = local_vars_tok & 0xFFFFFF;
2312 if (fat_header & FAT_HEADER_INVALID_FLAGS)
2313 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid fat signature flags %x", fat_header & FAT_HEADER_INVALID_FLAGS));
2315 if (ADDP_IS_GREATER_OR_OVF (ptr, code_size, end))
2316 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for code %d", code_size));
2318 if (!(fat_header & 0x08))
2319 return TRUE;
2321 ptr += code_size;
2323 do {
2324 unsigned section_header = 0, section_size = 0;
2325 gboolean is_fat;
2327 ptr = dword_align (ptr);
2328 if (!safe_read32 (section_header, ptr, end))
2329 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for data section header"));
2331 if (section_header & SECTION_HEADER_INVALID_FLAGS)
2332 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section header flags 0x%x", section_header & SECTION_HEADER_INVALID_FLAGS));
2334 is_fat = (section_header & METHOD_HEADER_SECTION_FAT_FORMAT) != 0;
2335 section_size = (section_header >> 8) & (is_fat ? 0xFFFFFF : 0xFF);
2337 if (section_size < 4)
2338 FAIL (ctx, g_strdup_printf ("MethodHeader: Section size too small"));
2340 if (ADDP_IS_GREATER_OR_OVF (ptr, section_size - 4, end)) /*must be section_size -4 as ptr was incremented by safe_read32*/
2341 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section content %d", section_size));
2343 if (section_header & METHOD_HEADER_SECTION_EHTABLE) {
2344 guint32 i, clauses = section_size / (is_fat ? 24 : 12);
2346 LAMEIMPL: MS emits section_size without accounting for header size.
2347 Mono does as the spec says. section_size is header + section
2348 MS's peverify happily accepts both.
2350 if ((clauses * (is_fat ? 24 : 12) != section_size) && (clauses * (is_fat ? 24 : 12) + 4 != section_size))
2351 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid EH section size %d, it's not of the expected size %d", section_size, clauses * (is_fat ? 24 : 12)));
2353 /* only verify the class token is verified as the rest is done by the IL verifier*/
2354 for (i = 0; i < clauses; ++i) {
2355 unsigned flags = *(unsigned char*)ptr;
2356 unsigned class_token = 0;
2357 ptr += (is_fat ? 20 : 8);
2358 if (!safe_read32 (class_token, ptr, end))
2359 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section %d", i));
2360 if (flags == MONO_EXCEPTION_CLAUSE_NONE && class_token) {
2361 guint table = mono_metadata_token_table (class_token);
2362 if (table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPESPEC)
2363 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token table %x", i, table));
2364 if (mono_metadata_token_index (class_token) > ctx->image->tables [table].rows)
2365 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token index %x", i, mono_metadata_token_index (class_token)));
2370 if (!(section_header & METHOD_HEADER_SECTION_MORE_SECTS))
2371 break;
2372 } while (1);
2373 return TRUE;
2376 static void
2377 verify_module_table (VerifyContext *ctx)
2379 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
2380 guint32 data [MONO_MODULE_SIZE];
2382 if (table->rows != 1)
2383 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
2385 mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
2387 if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
2388 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
2390 if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
2391 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
2393 if (data [MONO_MODULE_ENC] != 0)
2394 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
2396 if (data [MONO_MODULE_ENCBASE] != 0)
2397 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
2400 static void
2401 verify_typeref_table (VerifyContext *ctx)
2403 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
2404 MonoError error;
2405 guint32 i;
2407 for (i = 0; i < table->rows; ++i) {
2408 mono_verifier_verify_typeref_row (ctx->image, i, &error);
2409 add_from_mono_error (ctx, &error);
2413 /*bits 9,11,14,15,19,21,24-31 */
2414 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
2415 static void
2416 verify_typedef_table (VerifyContext *ctx)
2418 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2419 guint32 data [MONO_TYPEDEF_SIZE];
2420 guint32 fieldlist = 1, methodlist = 1, visibility;
2421 int i;
2423 if (table->rows == 0)
2424 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2426 for (i = 0; i < table->rows; ++i) {
2427 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2428 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
2429 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x rejected bits: 0x%08x", i, data [MONO_TYPEDEF_FLAGS], data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS));
2431 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
2432 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
2434 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
2435 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2437 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
2438 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2440 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) && (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
2441 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
2443 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
2444 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
2446 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
2447 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
2449 if (data [MONO_TYPEDEF_EXTENDS] && !is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
2450 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
2452 if (data [MONO_TYPEDEF_EXTENDS] && !get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
2453 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d zero coded extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
2455 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
2456 if ((visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) &&
2457 search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1) == -1)
2458 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d has nested visibility but no rows in the NestedClass table", i));
2460 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
2461 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
2463 if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2464 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
2466 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
2467 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x can't be smaller than of previous row 0x%08x", i, data [MONO_TYPEDEF_FIELD_LIST], fieldlist));
2469 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
2470 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
2472 if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
2473 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
2475 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
2476 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x can't be smaller than of previous row 0x%08x", i, data [MONO_TYPEDEF_METHOD_LIST], methodlist));
2478 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
2479 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
2483 static void
2484 verify_typedef_table_full (VerifyContext *ctx)
2486 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2487 guint32 data [MONO_TYPEDEF_SIZE];
2488 int i;
2490 if (table->rows == 0)
2491 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2493 for (i = 0; i < table->rows; ++i) {
2494 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2496 if (i == 0) {
2497 /*XXX it's ok if <module> extends object, or anything at all, actually. */
2498 /*if (data [MONO_TYPEDEF_EXTENDS] != 0)
2499 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
2501 continue;
2504 if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
2505 if (data [MONO_TYPEDEF_EXTENDS])
2506 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
2507 } else {
2508 gboolean is_sys_obj = typedef_is_system_object (ctx, data);
2509 gboolean has_parent = get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]) != 0;
2511 if (is_sys_obj) {
2512 if (has_parent)
2513 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
2514 } else {
2515 if (!has_parent) {
2516 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
2523 /*bits 3,11,14 */
2524 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
2525 static void
2526 verify_field_table (VerifyContext *ctx)
2528 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2529 guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
2530 int i;
2532 module_field_list = (guint32)-1;
2533 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2534 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2535 module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
2538 for (i = 0; i < table->rows; ++i) {
2539 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2540 flags = data [MONO_FIELD_FLAGS];
2542 if (flags & INVALID_FIELD_FLAG_BITS)
2543 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
2545 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)
2546 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
2548 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
2549 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
2551 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
2552 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
2554 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
2555 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
2557 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
2558 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
2559 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
2561 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
2562 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2563 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2565 if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
2566 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2567 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
2569 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
2570 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
2571 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2573 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
2574 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
2576 if (data [MONO_FIELD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_FIELD_SIGNATURE], 1))
2577 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature blob token 0x%x", i, data [MONO_FIELD_SIGNATURE]));
2579 //TODO verify contant flag
2581 if (i + 1 < module_field_list) {
2582 guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
2583 if (!(flags & FIELD_ATTRIBUTE_STATIC))
2584 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
2585 if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
2586 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
2591 static void
2592 verify_field_table_full (VerifyContext *ctx)
2594 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2595 guint32 data [MONO_FIELD_SIZE];
2596 int i;
2598 for (i = 0; i < table->rows; ++i) {
2599 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2601 if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
2602 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
2606 /*bits 8,9,10,11,13,14,15*/
2607 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
2608 static void
2609 verify_method_table (VerifyContext *ctx)
2611 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2612 guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
2613 guint32 paramlist = 1;
2614 gboolean is_ctor, is_cctor;
2615 const char *name;
2616 int i;
2618 module_method_list = (guint32)-1;
2619 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2620 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2621 module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
2624 for (i = 0; i < table->rows; ++i) {
2625 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2626 rva = data [MONO_METHOD_RVA];
2627 implflags = data [MONO_METHOD_IMPLFLAGS];
2628 flags = data [MONO_METHOD_FLAGS];
2629 access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
2630 code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
2633 if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
2634 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
2636 if (access == 0x7)
2637 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
2639 if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
2640 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
2642 name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
2643 is_ctor = !strcmp (".ctor", name);
2644 is_cctor = !strcmp (".cctor", name);
2646 if ((is_ctor || is_cctor) &&
2647 search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
2648 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
2650 if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
2651 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
2653 if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
2654 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
2655 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
2656 if (flags & METHOD_ATTRIBUTE_FINAL)
2657 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and Final", i));
2658 if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
2659 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
2662 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
2663 ADD_WARNING (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
2665 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
2666 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
2668 //XXX no checks against cas stuff 10,11,12,13)
2670 //TODO check iface with .ctor (15,16)
2672 if (i + 1 < module_method_list) {
2673 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2674 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
2675 if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
2676 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
2677 if (access == METHOD_ATTRIBUTE_FAMILY || access == METHOD_ATTRIBUTE_FAM_AND_ASSEM || access == METHOD_ATTRIBUTE_FAM_OR_ASSEM)
2678 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public, Private or Assembly", i));
2681 //TODO check valuetype for synchronized
2683 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
2684 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
2686 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
2687 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
2688 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
2689 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2690 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but not Static", i));
2693 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
2694 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2695 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
2697 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
2698 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
2700 //TODO check signature contents
2702 if (rva) {
2703 if ((flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) || (implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
2704 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is either Abstract, InternalCall or PinvokeImpl", i));
2705 if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
2706 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
2707 } else {
2708 if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2709 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
2712 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2713 if (rva)
2714 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
2715 if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
2716 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
2718 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
2719 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
2721 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
2722 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
2724 if (data [MONO_METHOD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHOD_SIGNATURE], 1))
2725 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature blob token 0x%x", i, data [MONO_METHOD_SIGNATURE]));
2727 if (data [MONO_METHOD_PARAMLIST] == 0)
2728 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
2730 if (data [MONO_METHOD_PARAMLIST] < paramlist)
2731 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x can't be smaller than of previous row 0x%08x", i, data [MONO_METHOD_PARAMLIST], paramlist));
2733 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
2734 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
2736 paramlist = data [MONO_METHOD_PARAMLIST];
2741 static void
2742 verify_method_table_full (VerifyContext *ctx)
2744 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2745 guint32 data [MONO_METHOD_SIZE], rva, locals_token;
2746 int i;
2748 for (i = 0; i < table->rows; ++i) {
2749 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2750 rva = data [MONO_METHOD_RVA];
2752 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
2753 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
2755 if (rva && !is_valid_method_header (ctx, rva, &locals_token))
2756 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
2760 static guint32
2761 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
2763 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2764 guint32 row = *current_method;
2765 guint32 paramlist, tmp;
2768 paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
2769 while (row < table->rows) {
2770 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
2771 if (tmp > paramlist) {
2772 *current_method = row;
2773 return tmp - paramlist;
2775 ++row;
2778 /*no more methods, all params apply to the last one*/
2779 *current_method = table->rows;
2780 return (guint32)-1;
2784 #define INVALID_PARAM_FLAGS_BITS ((1 << 2) | (1 << 3) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 14) | (1 << 15))
2785 static void
2786 verify_param_table (VerifyContext *ctx)
2788 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
2789 guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
2790 gboolean first_param = TRUE;
2791 int i;
2793 if (ctx->image->tables [MONO_TABLE_METHOD].rows == 0) {
2794 if (table->rows > 0)
2795 ADD_ERROR (ctx, g_strdup ("Param table has rows while the method table has zero"));
2796 return;
2799 remaining_params = get_next_param_count (ctx, &current_method);
2801 for (i = 0; i < table->rows; ++i) {
2802 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
2803 flags = data [MONO_PARAM_FLAGS];
2805 if (flags & INVALID_PARAM_FLAGS_BITS)
2806 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
2808 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
2809 if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
2810 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
2811 } else {
2812 if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
2813 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
2816 if ((flags & PARAM_ATTRIBUTE_HAS_FIELD_MARSHAL) && search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_PARAM, i)) == -1)
2817 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
2819 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
2820 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
2822 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
2823 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
2825 first_param = FALSE;
2826 sequence = data [MONO_PARAM_SEQUENCE];
2827 if (--remaining_params == 0) {
2828 remaining_params = get_next_param_count (ctx, &current_method);
2829 first_param = TRUE;
2834 static void
2835 verify_interfaceimpl_table (VerifyContext *ctx)
2837 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
2838 guint32 data [MONO_INTERFACEIMPL_SIZE];
2839 int i;
2841 for (i = 0; i < table->rows; ++i) {
2842 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
2843 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2844 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_INTERFACEIMPL_CLASS]));
2846 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2847 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
2849 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2850 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
2854 static void
2855 verify_memberref_table (VerifyContext *ctx)
2857 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2858 guint32 data [MONO_MEMBERREF_SIZE];
2859 int i;
2861 for (i = 0; i < table->rows; ++i) {
2862 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2864 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2865 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
2867 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2868 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
2870 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
2871 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
2873 if (data [MONO_MEMBERREF_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_MEMBERREF_SIGNATURE], 1))
2874 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d invalid signature blob token 0x%x", i, data [MONO_MEMBERREF_SIGNATURE]));
2879 static void
2880 verify_memberref_table_full (VerifyContext *ctx)
2882 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2883 guint32 data [MONO_MEMBERREF_SIZE];
2884 int i;
2886 for (i = 0; i < table->rows; ++i) {
2887 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2889 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
2890 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field 0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
2894 static void
2895 verify_constant_table (VerifyContext *ctx)
2897 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
2898 guint32 data [MONO_CONSTANT_SIZE], type;
2899 int i;
2901 for (i = 0; i < table->rows; ++i) {
2902 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
2903 type = data [MONO_CONSTANT_TYPE];
2905 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
2906 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
2908 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2909 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
2911 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2912 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
2914 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
2915 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
2919 static void
2920 verify_cattr_table (VerifyContext *ctx)
2922 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2923 guint32 data [MONO_CUSTOM_ATTR_SIZE];
2924 int i;
2926 for (i = 0; i < table->rows; ++i) {
2927 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2929 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
2930 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2932 if (!is_valid_coded_index (ctx, CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]) || !get_coded_index_token (CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]))
2933 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Type field 0x%08x", i, data [MONO_CUSTOM_ATTR_TYPE]));
2935 if (data [MONO_CUSTOM_ATTR_VALUE] && !is_valid_blob_object (ctx, data [MONO_CUSTOM_ATTR_VALUE], 0))
2936 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d invalid value blob 0x%x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2940 static void
2941 verify_cattr_table_full (VerifyContext *ctx)
2943 MonoError error;
2944 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2945 MonoMethod *ctor;
2946 const char *ptr;
2947 guint32 data [MONO_CUSTOM_ATTR_SIZE], mtoken, size;
2948 int i;
2950 for (i = 0; i < table->rows; ++i) {
2951 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2953 if (!is_valid_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
2954 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2956 mtoken = data [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
2957 switch (data [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
2958 case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
2959 mtoken |= MONO_TOKEN_METHOD_DEF;
2960 break;
2961 case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
2962 mtoken |= MONO_TOKEN_MEMBER_REF;
2963 break;
2964 default:
2965 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute constructor row %d Token 0x%08x", i, data [MONO_CUSTOM_ATTR_TYPE]));
2968 ctor = mono_get_method_checked (ctx->image, mtoken, NULL, NULL, &error);
2970 if (!ctor) {
2971 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute content row %d Could not load ctor due to %s", i, mono_error_get_message (&error)));
2972 mono_error_cleanup (&error);
2975 /*This can't fail since this is checked in is_valid_cattr_blob*/
2976 g_assert (decode_signature_header (ctx, data [MONO_CUSTOM_ATTR_VALUE], &size, &ptr));
2978 if (!is_valid_cattr_content (ctx, ctor, ptr, size)) {
2979 char *ctor_name = mono_method_full_name (ctor, TRUE);
2980 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute content row %d Value field 0x%08x ctor: %s", i, data [MONO_CUSTOM_ATTR_VALUE], ctor_name));
2981 g_free (ctor_name);
2986 static void
2987 verify_field_marshal_table (VerifyContext *ctx)
2989 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2990 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2991 int i;
2993 for (i = 0; i < table->rows; ++i) {
2994 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2996 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2997 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
2999 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
3000 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
3002 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
3003 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
3005 if (!is_valid_blob_object (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE], 1))
3006 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d invalid NativeType blob 0x%x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
3010 static void
3011 verify_field_marshal_table_full (VerifyContext *ctx)
3013 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
3014 guint32 data [MONO_FIELD_MARSHAL_SIZE];
3015 int i;
3017 for (i = 0; i < table->rows; ++i) {
3018 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
3020 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
3021 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
3025 static void
3026 verify_decl_security_table (VerifyContext *ctx)
3028 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
3029 guint32 data [MONO_DECL_SECURITY_SIZE];
3030 int i;
3032 for (i = 0; i < table->rows; ++i) {
3033 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
3035 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
3036 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
3038 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
3039 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
3041 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
3042 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
3046 static void
3047 verify_decl_security_table_full (VerifyContext *ctx)
3049 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
3050 guint32 data [MONO_DECL_SECURITY_SIZE];
3051 int i;
3053 for (i = 0; i < table->rows; ++i) {
3054 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
3056 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
3057 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
3061 static void
3062 verify_class_layout_table (VerifyContext *ctx)
3064 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
3065 guint32 data [MONO_CLASS_LAYOUT_SIZE];
3066 int i;
3068 for (i = 0; i < table->rows; ++i) {
3069 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
3071 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3072 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
3074 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
3075 case 0:
3076 case 1:
3077 case 2:
3078 case 4:
3079 case 8:
3080 case 16:
3081 case 32:
3082 case 64:
3083 case 128:
3084 break;
3085 default:
3086 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
3091 static void
3092 verify_field_layout_table (VerifyContext *ctx)
3094 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
3095 guint32 data [MONO_FIELD_LAYOUT_SIZE];
3096 int i;
3098 for (i = 0; i < table->rows; ++i) {
3099 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
3101 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
3102 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
3106 static void
3107 verify_standalonesig_table (VerifyContext *ctx)
3109 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
3110 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
3111 int i;
3113 for (i = 0; i < table->rows; ++i) {
3114 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
3116 if (data [MONO_STAND_ALONE_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_STAND_ALONE_SIGNATURE], 1))
3117 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d invalid signature 0x%x", i, data [MONO_STAND_ALONE_SIGNATURE]));
3121 static void
3122 verify_standalonesig_table_full (VerifyContext *ctx)
3124 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
3125 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
3126 int i;
3128 for (i = 0; i < table->rows; ++i) {
3129 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
3131 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
3132 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
3136 static void
3137 verify_eventmap_table (VerifyContext *ctx)
3139 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
3140 guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
3141 int i;
3143 for (i = 0; i < table->rows; ++i) {
3144 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
3146 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3147 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
3149 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
3150 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
3152 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
3156 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
3157 static void
3158 verify_event_table (VerifyContext *ctx)
3160 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
3161 guint32 data [MONO_EVENT_SIZE];
3162 int i;
3164 for (i = 0; i < table->rows; ++i) {
3165 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
3167 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
3168 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
3170 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
3171 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
3173 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
3174 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
3178 static void
3179 verify_event_table_full (VerifyContext *ctx)
3181 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
3182 MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
3183 guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
3184 gboolean found_add, found_remove;
3185 int i, idx;
3187 for (i = 0; i < table->rows; ++i) {
3188 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
3190 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
3191 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
3192 if (idx == -1)
3193 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
3195 //first we move to the first row for this event
3196 while (idx > 0) {
3197 if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
3198 break;
3199 --idx;
3201 //now move forward looking for AddOn and RemoveOn rows
3202 found_add = found_remove = FALSE;
3203 while (idx < sema_table->rows) {
3204 mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
3205 if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
3206 break;
3207 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
3208 found_add = TRUE;
3209 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
3210 found_remove = TRUE;
3211 if (found_add && found_remove)
3212 break;
3213 ++idx;
3216 if (!found_add)
3217 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
3218 if (!found_remove)
3219 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no RemoveOn associated method", i));
3223 static void
3224 verify_propertymap_table (VerifyContext *ctx)
3226 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
3227 guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
3228 int i;
3230 for (i = 0; i < table->rows; ++i) {
3231 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
3233 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3234 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
3236 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
3237 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
3239 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
3243 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
3244 static void
3245 verify_property_table (VerifyContext *ctx)
3247 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
3248 guint32 data [MONO_PROPERTY_SIZE];
3249 int i;
3251 for (i = 0; i < table->rows; ++i) {
3252 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
3254 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
3255 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
3257 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
3258 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
3260 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
3261 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
3263 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
3264 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
3265 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
3270 static void
3271 verify_methodimpl_table (VerifyContext *ctx)
3273 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
3274 guint32 data [MONO_METHODIMPL_SIZE];
3275 int i;
3277 for (i = 0; i < table->rows; ++i) {
3278 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
3280 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3281 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
3283 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
3284 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
3286 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
3287 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
3289 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
3290 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
3292 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
3293 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
3297 static void
3298 verify_moduleref_table (VerifyContext *ctx)
3300 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
3301 guint32 data [MONO_MODULEREF_SIZE];
3302 int i;
3304 for (i = 0; i < table->rows; ++i) {
3305 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
3307 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
3308 ADD_ERROR (ctx, g_strdup_printf ("Invalid ModuleRef row %d name field %08x", i, data [MONO_MODULEREF_NAME]));
3312 static void
3313 verify_typespec_table (VerifyContext *ctx)
3315 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
3316 guint32 data [MONO_TYPESPEC_SIZE];
3317 int i;
3319 for (i = 0; i < table->rows; ++i) {
3320 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
3322 if (data [MONO_TYPESPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_TYPESPEC_SIGNATURE], 1))
3323 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
3327 static void
3328 verify_typespec_table_full (VerifyContext *ctx)
3330 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
3331 guint32 data [MONO_TYPESPEC_SIZE];
3332 int i;
3334 for (i = 0; i < table->rows; ++i) {
3335 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
3336 ctx->token = (i + 1) | MONO_TOKEN_TYPE_SPEC;
3337 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
3338 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
3340 ctx->token = 0;
3343 #define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 12) | (1 << 13))
3344 static void
3345 verify_implmap_table (VerifyContext *ctx)
3347 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
3348 guint32 data [MONO_IMPLMAP_SIZE], cconv;
3349 int i;
3351 for (i = 0; i < table->rows; ++i) {
3352 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
3354 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
3355 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
3357 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
3358 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
3359 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
3361 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
3362 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
3364 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
3365 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
3367 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
3368 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
3370 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
3371 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
3373 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULEREF].rows)
3374 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
3378 static void
3379 verify_fieldrva_table (VerifyContext *ctx)
3381 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
3382 guint32 data [MONO_FIELD_RVA_SIZE];
3383 int i;
3385 for (i = 0; i < table->rows; ++i) {
3386 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
3388 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
3389 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
3391 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
3392 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
3396 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 14) | (1 << 15))
3397 static void
3398 verify_assembly_table (VerifyContext *ctx)
3400 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
3401 guint32 data [MONO_ASSEMBLY_SIZE], hash;
3402 int i;
3404 if (table->rows > 1)
3405 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
3407 for (i = 0; i < table->rows; ++i) {
3408 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
3410 hash = data [MONO_ASSEMBLY_HASH_ALG];
3411 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
3412 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
3414 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
3415 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
3417 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY], 1))
3418 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
3420 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
3421 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
3423 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
3424 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
3428 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~((1 << 0) | (1 << 8) | (1 << 14) | (1 << 15))
3429 static void
3430 verify_assemblyref_table (VerifyContext *ctx)
3432 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
3433 guint32 data [MONO_ASSEMBLYREF_SIZE];
3434 int i;
3436 for (i = 0; i < table->rows; ++i) {
3437 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
3439 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
3440 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
3442 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY], 1))
3443 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
3445 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
3446 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
3448 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
3449 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
3451 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE], 1))
3452 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
3456 #define INVALID_FILE_FLAGS_BITS ~(1)
3457 static void
3458 verify_file_table (VerifyContext *ctx)
3460 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
3461 guint32 data [MONO_FILE_SIZE];
3462 int i;
3464 for (i = 0; i < table->rows; ++i) {
3465 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
3467 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
3468 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
3470 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
3471 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
3473 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE], 1))
3474 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
3478 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
3479 static void
3480 verify_exportedtype_table (VerifyContext *ctx)
3482 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
3483 guint32 data [MONO_EXP_TYPE_SIZE];
3484 int i;
3486 for (i = 0; i < table->rows; ++i) {
3487 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
3489 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
3490 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
3492 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
3493 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
3495 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
3496 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
3498 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3499 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
3501 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3502 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
3504 /*nested type can't have a namespace*/
3505 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
3506 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
3510 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
3511 static void
3512 verify_manifest_resource_table (VerifyContext *ctx)
3514 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)ctx->image->image_info;
3515 MonoCLIHeader *ch = &iinfo->cli_cli_header;
3516 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
3517 guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
3518 int i;
3520 resources_size = ch->ch_resources.size;
3522 for (i = 0; i < table->rows; ++i) {
3523 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
3525 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
3526 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
3528 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
3529 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
3531 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
3532 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
3534 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
3535 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
3537 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3538 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3540 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
3541 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token table %08x", i, get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION])));
3543 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
3544 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
3546 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
3547 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
3551 static void
3552 verify_nested_class_table (VerifyContext *ctx)
3554 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3555 guint32 data [MONO_NESTED_CLASS_SIZE];
3556 int i;
3558 for (i = 0; i < table->rows; ++i) {
3559 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
3561 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3562 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
3563 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3564 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3565 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
3566 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3570 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
3571 static void
3572 verify_generic_param_table (VerifyContext *ctx)
3574 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
3575 guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
3576 int i, param_number = 0;
3578 for (i = 0; i < table->rows; ++i) {
3579 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
3581 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
3582 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
3584 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
3585 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
3587 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
3588 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
3590 token = data [MONO_GENERICPARAM_OWNER];
3592 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
3593 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
3595 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
3596 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
3598 if (token != last_token) {
3599 param_number = 0;
3600 last_token = token;
3603 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
3604 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d Number is out of order %d expected %d", i, data [MONO_GENERICPARAM_NUMBER], param_number));
3606 ++param_number;
3610 static void
3611 verify_method_spec_table (VerifyContext *ctx)
3613 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3614 guint32 data [MONO_METHODSPEC_SIZE];
3615 int i;
3617 for (i = 0; i < table->rows; ++i) {
3618 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3620 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3621 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
3623 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3624 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
3626 if (data [MONO_METHODSPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHODSPEC_SIGNATURE], 1))
3627 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid signature token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3631 static void
3632 verify_method_spec_table_full (VerifyContext *ctx)
3634 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3635 guint32 data [MONO_METHODSPEC_SIZE];
3636 int i;
3638 for (i = 0; i < table->rows; ++i) {
3639 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3641 if (!is_valid_methodspec_blob (ctx, data [MONO_METHODSPEC_SIGNATURE]))
3642 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3646 static void
3647 verify_generic_param_constraint_table (VerifyContext *ctx)
3649 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
3650 guint32 data [MONO_GENPARCONSTRAINT_SIZE];
3651 int i;
3652 guint32 last_owner = 0, last_constraint = 0;
3654 for (i = 0; i < table->rows; ++i) {
3655 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
3657 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
3658 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_GENPARCONSTRAINT_GENERICPAR]));
3660 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3661 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
3663 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3664 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
3666 if (last_owner > data [MONO_GENPARCONSTRAINT_GENERICPAR])
3667 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d is not properly sorted. Previous value of the owner column is 0x%08x current value is 0x%08x", i, last_owner, data [MONO_GENPARCONSTRAINT_GENERICPAR]));
3669 if (last_owner == data [MONO_GENPARCONSTRAINT_GENERICPAR]) {
3670 if (last_constraint == data [MONO_GENPARCONSTRAINT_CONSTRAINT])
3671 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has duplicate constraint 0x%08x", i, last_constraint));
3672 } else {
3673 last_owner = data [MONO_GENPARCONSTRAINT_GENERICPAR];
3675 last_constraint = data [MONO_GENPARCONSTRAINT_CONSTRAINT];
3680 typedef struct {
3681 const char *name;
3682 const char *name_space;
3683 guint32 resolution_scope;
3684 } TypeDefUniqueId;
3686 static guint
3687 typedef_hash (gconstpointer _key)
3689 const TypeDefUniqueId *key = (const TypeDefUniqueId *)_key;
3690 return g_str_hash (key->name) ^ g_str_hash (key->name_space) ^ key->resolution_scope; /*XXX better salt the int key*/
3693 static gboolean
3694 typedef_equals (gconstpointer _a, gconstpointer _b)
3696 const TypeDefUniqueId *a = (const TypeDefUniqueId *)_a;
3697 const TypeDefUniqueId *b = (const TypeDefUniqueId *)_b;
3698 return !strcmp (a->name, b->name) && !strcmp (a->name_space, b->name_space) && a->resolution_scope == b->resolution_scope;
3701 static void
3702 verify_typedef_table_global_constraints (VerifyContext *ctx)
3704 int i;
3705 guint32 data [MONO_TYPEDEF_SIZE];
3706 guint32 nested_data [MONO_NESTED_CLASS_SIZE];
3707 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
3708 MonoTableInfo *nested_table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3709 GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3711 for (i = 0; i < table->rows; ++i) {
3712 guint visibility;
3713 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3714 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
3716 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAME]);
3717 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAMESPACE]);
3718 type->resolution_scope = 0;
3720 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
3721 if (visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) {
3722 int res = search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1);
3723 g_assert (res >= 0);
3725 mono_metadata_decode_row (nested_table, res, nested_data, MONO_NESTED_CLASS_SIZE);
3726 type->resolution_scope = nested_data [MONO_NESTED_CLASS_ENCLOSING];
3729 if (g_hash_table_lookup (unique_types, type)) {
3730 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("TypeDef table row %d has duplicate for tuple (%s,%s,%x)", i, type->name, type->name_space, type->resolution_scope));
3731 g_hash_table_destroy (unique_types);
3732 g_free (type);
3733 return;
3735 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3738 g_hash_table_destroy (unique_types);
3741 static void
3742 verify_typeref_table_global_constraints (VerifyContext *ctx)
3744 int i;
3745 guint32 data [MONO_TYPEREF_SIZE];
3746 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
3747 GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3749 for (i = 0; i < table->rows; ++i) {
3750 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3751 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
3753 type->resolution_scope = data [MONO_TYPEREF_SCOPE];
3754 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAME]);
3755 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAMESPACE]);
3757 if (g_hash_table_lookup (unique_types, type)) {
3758 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("TypeRef table row %d has duplicate for tuple (%s,%s,%x)", i, type->name, type->name_space, type->resolution_scope));
3759 g_hash_table_destroy (unique_types);
3760 g_free (type);
3761 return;
3763 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3766 g_hash_table_destroy (unique_types);
3769 typedef struct {
3770 guint32 klass;
3771 guint32 method_declaration;
3772 } MethodImplUniqueId;
3774 static guint
3775 methodimpl_hash (gconstpointer _key)
3777 const MethodImplUniqueId *key = (const MethodImplUniqueId *)_key;
3778 return key->klass ^ key->method_declaration;
3781 static gboolean
3782 methodimpl_equals (gconstpointer _a, gconstpointer _b)
3784 const MethodImplUniqueId *a = (const MethodImplUniqueId *)_a;
3785 const MethodImplUniqueId *b = (const MethodImplUniqueId *)_b;
3786 return a->klass == b->klass && a->method_declaration == b->method_declaration;
3789 static void
3790 verify_methodimpl_table_global_constraints (VerifyContext *ctx)
3792 int i;
3793 guint32 data [MONO_METHODIMPL_SIZE];
3794 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
3795 GHashTable *unique_impls = g_hash_table_new_full (&methodimpl_hash, &methodimpl_equals, g_free, NULL);
3797 for (i = 0; i < table->rows; ++i) {
3798 MethodImplUniqueId *impl = g_new (MethodImplUniqueId, 1);
3799 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
3801 impl->klass = data [MONO_METHODIMPL_CLASS];
3802 impl->method_declaration = data [MONO_METHODIMPL_DECLARATION];
3804 if (g_hash_table_lookup (unique_impls, impl)) {
3805 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("MethodImpl table row %d has duplicate for tuple (0x%x, 0x%x)", impl->klass, impl->method_declaration));
3806 g_hash_table_destroy (unique_impls);
3807 g_free (impl);
3808 return;
3810 g_hash_table_insert (unique_impls, impl, GUINT_TO_POINTER (1));
3813 g_hash_table_destroy (unique_impls);
3817 static void
3818 verify_tables_data_global_constraints (VerifyContext *ctx)
3820 verify_typedef_table_global_constraints (ctx);
3823 static void
3824 verify_tables_data_global_constraints_full (VerifyContext *ctx)
3826 verify_typeref_table (ctx);
3827 verify_typeref_table_global_constraints (ctx);
3828 verify_methodimpl_table_global_constraints (ctx);
3831 static void
3832 verify_tables_data (VerifyContext *ctx)
3834 OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
3835 guint32 size = 0, tables_offset;
3836 int i;
3838 for (i = 0; i < 0x2D; ++i) {
3839 MonoTableInfo *table = &ctx->image->tables [i];
3840 guint32 tmp_size;
3841 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
3842 if (tmp_size < size) {
3843 size = 0;
3844 break;
3846 size = tmp_size;
3849 if (size == 0)
3850 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
3852 tables_offset = ctx->image->tables_base - ctx->data;
3853 if (!bounds_check_offset (&tables_area, tables_offset, size))
3854 ADD_ERROR (ctx, g_strdup_printf ("Tables data require %d bytes but the only %d are available in the #~ stream", size, tables_area.size - (tables_offset - tables_area.offset)));
3856 verify_module_table (ctx);
3857 CHECK_ERROR ();
3858 /*Obfuscators love to place broken stuff in the typeref table
3859 verify_typeref_table (ctx);
3860 CHECK_ERROR ();*/
3861 verify_typedef_table (ctx);
3862 CHECK_ERROR ();
3863 verify_field_table (ctx);
3864 CHECK_ERROR ();
3865 verify_method_table (ctx);
3866 CHECK_ERROR ();
3867 verify_param_table (ctx);
3868 CHECK_ERROR ();
3869 verify_interfaceimpl_table (ctx);
3870 CHECK_ERROR ();
3871 verify_memberref_table (ctx);
3872 CHECK_ERROR ();
3873 verify_constant_table (ctx);
3874 CHECK_ERROR ();
3875 verify_cattr_table (ctx);
3876 CHECK_ERROR ();
3877 verify_field_marshal_table (ctx);
3878 CHECK_ERROR ();
3879 verify_decl_security_table (ctx);
3880 CHECK_ERROR ();
3881 verify_class_layout_table (ctx);
3882 CHECK_ERROR ();
3883 verify_field_layout_table (ctx);
3884 CHECK_ERROR ();
3885 verify_standalonesig_table (ctx);
3886 CHECK_ERROR ();
3887 verify_eventmap_table (ctx);
3888 CHECK_ERROR ();
3889 verify_event_table (ctx);
3890 CHECK_ERROR ();
3891 verify_propertymap_table (ctx);
3892 CHECK_ERROR ();
3893 verify_property_table (ctx);
3894 CHECK_ERROR ();
3895 verify_methodimpl_table (ctx);
3896 CHECK_ERROR ();
3897 verify_moduleref_table (ctx);
3898 CHECK_ERROR ();
3899 verify_typespec_table (ctx);
3900 CHECK_ERROR ();
3901 verify_implmap_table (ctx);
3902 CHECK_ERROR ();
3903 verify_fieldrva_table (ctx);
3904 CHECK_ERROR ();
3905 verify_assembly_table (ctx);
3906 CHECK_ERROR ();
3907 verify_assemblyref_table (ctx);
3908 CHECK_ERROR ();
3909 verify_file_table (ctx);
3910 CHECK_ERROR ();
3911 verify_exportedtype_table (ctx);
3912 CHECK_ERROR ();
3913 verify_manifest_resource_table (ctx);
3914 CHECK_ERROR ();
3915 verify_nested_class_table (ctx);
3916 CHECK_ERROR ();
3917 verify_generic_param_table (ctx);
3918 CHECK_ERROR ();
3919 verify_method_spec_table (ctx);
3920 CHECK_ERROR ();
3921 verify_generic_param_constraint_table (ctx);
3922 CHECK_ERROR ();
3923 verify_tables_data_global_constraints (ctx);
3926 static void
3927 init_verify_context (VerifyContext *ctx, MonoImage *image, gboolean report_error)
3929 memset (ctx, 0, sizeof (VerifyContext));
3930 ctx->image = image;
3931 ctx->report_error = report_error;
3932 ctx->report_warning = FALSE; //export this setting in the API
3933 ctx->valid = 1;
3934 ctx->size = image->raw_data_len;
3935 ctx->data = image->raw_data;
3938 static gboolean
3939 cleanup_context (VerifyContext *ctx, GSList **error_list)
3941 g_free (ctx->sections);
3942 if (error_list)
3943 *error_list = ctx->errors;
3944 else
3945 mono_free_verify_list (ctx->errors);
3946 return ctx->valid;
3949 static gboolean
3950 cleanup_context_checked (VerifyContext *ctx, MonoError *error)
3952 g_free (ctx->sections);
3953 if (ctx->errors) {
3954 MonoVerifyInfo *info = (MonoVerifyInfo *)ctx->errors->data;
3955 mono_error_set_bad_image (error, ctx->image, "%s", info->message);
3956 mono_free_verify_list (ctx->errors);
3958 return ctx->valid;
3961 gboolean
3962 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3964 VerifyContext ctx;
3966 if (!mono_verifier_is_enabled_for_image (image))
3967 return TRUE;
3969 init_verify_context (&ctx, image, error_list != NULL);
3970 ctx.stage = STAGE_PE;
3972 verify_msdos_header (&ctx);
3973 CHECK_STATE();
3974 verify_pe_header (&ctx);
3975 CHECK_STATE();
3976 verify_pe_optional_header (&ctx);
3977 CHECK_STATE();
3978 load_section_table (&ctx);
3979 CHECK_STATE();
3980 load_data_directories (&ctx);
3981 CHECK_STATE();
3982 verify_import_table (&ctx);
3983 CHECK_STATE();
3984 /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
3985 verify_resources_table (&ctx);
3987 cleanup:
3988 return cleanup_context (&ctx, error_list);
3991 gboolean
3992 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3994 VerifyContext ctx;
3996 if (!mono_verifier_is_enabled_for_image (image))
3997 return TRUE;
3999 init_verify_context (&ctx, image, error_list != NULL);
4000 ctx.stage = STAGE_CLI;
4002 verify_cli_header (&ctx);
4003 CHECK_STATE();
4004 verify_metadata_header (&ctx);
4005 CHECK_STATE();
4006 verify_tables_schema (&ctx);
4008 cleanup:
4009 return cleanup_context (&ctx, error_list);
4014 * Verifies basic table constraints such as global table invariants (sorting, field monotonicity, etc).
4015 * Other verification checks are meant to be done lazily by the runtime. Those include:
4016 * blob items (signatures, method headers, custom attributes, etc)
4017 * type semantics related
4018 * vtable related
4019 * stuff that should not block other pieces from running such as bad types/methods/fields/etc.
4021 * The whole idea is that if this succeed the runtime is free to play around safely but any complex
4022 * operation still need more checking.
4024 gboolean
4025 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
4027 VerifyContext ctx;
4029 if (!mono_verifier_is_enabled_for_image (image))
4030 return TRUE;
4032 init_verify_context (&ctx, image, error_list != NULL);
4033 ctx.stage = STAGE_TABLES;
4035 verify_tables_data (&ctx);
4037 return cleanup_context (&ctx, error_list);
4042 * Verifies all other constraints.
4044 gboolean
4045 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
4047 VerifyContext ctx;
4049 if (!mono_verifier_is_enabled_for_image (image))
4050 return TRUE;
4052 init_verify_context (&ctx, image, error_list != NULL);
4053 ctx.stage = STAGE_TABLES;
4055 verify_typedef_table_full (&ctx);
4056 CHECK_STATE ();
4057 verify_field_table_full (&ctx);
4058 CHECK_STATE ();
4059 verify_method_table_full (&ctx);
4060 CHECK_STATE ();
4061 verify_memberref_table_full (&ctx);
4062 CHECK_STATE ();
4063 verify_cattr_table_full (&ctx);
4064 CHECK_STATE ();
4065 verify_field_marshal_table_full (&ctx);
4066 CHECK_STATE ();
4067 verify_decl_security_table_full (&ctx);
4068 CHECK_STATE ();
4069 verify_standalonesig_table_full (&ctx);
4070 CHECK_STATE ();
4071 verify_event_table_full (&ctx);
4072 CHECK_STATE ();
4073 verify_typespec_table_full (&ctx);
4074 CHECK_STATE ();
4075 verify_method_spec_table_full (&ctx);
4076 CHECK_STATE ();
4077 verify_tables_data_global_constraints_full (&ctx);
4079 cleanup:
4080 return cleanup_context (&ctx, error_list);
4083 gboolean
4084 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4086 VerifyContext ctx;
4088 if (!mono_verifier_is_enabled_for_image (image))
4089 return TRUE;
4091 init_verify_context (&ctx, image, error_list != NULL);
4092 ctx.stage = STAGE_TABLES;
4094 is_valid_field_signature (&ctx, offset);
4095 return cleanup_context (&ctx, error_list);
4098 gboolean
4099 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
4101 VerifyContext ctx;
4102 guint32 locals_token;
4104 if (!mono_verifier_is_enabled_for_image (image))
4105 return TRUE;
4107 init_verify_context (&ctx, image, error_list != NULL);
4108 ctx.stage = STAGE_TABLES;
4110 is_valid_method_header (&ctx, offset, &locals_token);
4111 if (locals_token) {
4112 guint32 sig_offset = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_STANDALONESIG], locals_token - 1, MONO_STAND_ALONE_SIGNATURE);
4113 is_valid_standalonesig_blob (&ctx, sig_offset);
4116 return cleanup_context (&ctx, error_list);
4119 gboolean
4120 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, MonoError *error)
4122 VerifyContext ctx;
4124 error_init (error);
4126 if (!mono_verifier_is_enabled_for_image (image))
4127 return TRUE;
4129 init_verify_context (&ctx, image, TRUE);
4130 ctx.stage = STAGE_TABLES;
4132 is_valid_method_signature (&ctx, offset);
4133 /*XXX This returns a bad image exception, it might be the case that the right exception is method load.*/
4134 return cleanup_context_checked (&ctx, error);
4137 gboolean
4138 mono_verifier_verify_memberref_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
4140 VerifyContext ctx;
4142 if (!mono_verifier_is_enabled_for_image (image))
4143 return TRUE;
4145 init_verify_context (&ctx, image, error_list != NULL);
4146 ctx.stage = STAGE_TABLES;
4148 is_valid_memberref_method_signature (&ctx, offset);
4149 return cleanup_context (&ctx, error_list);
4152 gboolean
4153 mono_verifier_verify_memberref_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4155 VerifyContext ctx;
4157 if (!mono_verifier_is_enabled_for_image (image))
4158 return TRUE;
4160 init_verify_context (&ctx, image, error_list != NULL);
4161 ctx.stage = STAGE_TABLES;
4163 is_valid_field_signature (&ctx, offset);
4164 return cleanup_context (&ctx, error_list);
4167 gboolean
4168 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
4170 VerifyContext ctx;
4172 if (!mono_verifier_is_enabled_for_image (image))
4173 return TRUE;
4175 init_verify_context (&ctx, image, error_list != NULL);
4176 ctx.stage = STAGE_TABLES;
4178 is_valid_standalonesig_blob (&ctx, offset);
4179 return cleanup_context (&ctx, error_list);
4182 gboolean
4183 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
4185 VerifyContext ctx;
4187 if (!mono_verifier_is_enabled_for_image (image))
4188 return TRUE;
4190 init_verify_context (&ctx, image, error_list != NULL);
4191 ctx.stage = STAGE_TABLES;
4192 ctx.token = token;
4194 is_valid_typespec_blob (&ctx, offset);
4195 return cleanup_context (&ctx, error_list);
4198 gboolean
4199 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
4201 VerifyContext ctx;
4203 if (!mono_verifier_is_enabled_for_image (image))
4204 return TRUE;
4206 init_verify_context (&ctx, image, error_list != NULL);
4207 ctx.stage = STAGE_TABLES;
4209 is_valid_methodspec_blob (&ctx, offset);
4210 return cleanup_context (&ctx, error_list);
4213 static void
4214 verify_user_string (VerifyContext *ctx, guint32 offset)
4216 OffsetAndSize heap_us = get_metadata_stream (ctx, &ctx->image->heap_us);
4217 guint32 entry_size, bytes;
4219 if (heap_us.size < offset)
4220 ADD_ERROR (ctx, g_strdup ("User string offset beyond heap_us size"));
4222 if (!decode_value (ctx->data + offset + heap_us.offset, heap_us.size - heap_us.offset, &entry_size, &bytes))
4223 ADD_ERROR (ctx, g_strdup ("Could not decode user string blob size"));
4225 if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
4226 ADD_ERROR (ctx, g_strdup ("User string size overflow"));
4228 entry_size += bytes;
4230 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, heap_us.size))
4231 ADD_ERROR (ctx, g_strdup ("User string oveflow heap_us"));
4234 gboolean
4235 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
4237 VerifyContext ctx;
4239 if (!mono_verifier_is_enabled_for_image (image))
4240 return TRUE;
4242 init_verify_context (&ctx, image, error_list != NULL);
4243 ctx.stage = STAGE_TABLES;
4245 verify_user_string (&ctx, offset);
4247 return cleanup_context (&ctx, error_list);
4250 gboolean
4251 mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, GSList **error_list)
4253 VerifyContext ctx;
4255 if (!mono_verifier_is_enabled_for_image (image))
4256 return TRUE;
4258 init_verify_context (&ctx, image, error_list != NULL);
4259 ctx.stage = STAGE_TABLES;
4261 is_valid_cattr_blob (&ctx, offset);
4263 return cleanup_context (&ctx, error_list);
4266 gboolean
4267 mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, GSList **error_list)
4269 VerifyContext ctx;
4271 if (!mono_verifier_is_enabled_for_image (image))
4272 return TRUE;
4274 init_verify_context (&ctx, image, error_list != NULL);
4275 ctx.stage = STAGE_TABLES;
4277 is_valid_cattr_content (&ctx, ctor, (const char*)data, size);
4279 return cleanup_context (&ctx, error_list);
4282 gboolean
4283 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
4285 MonoMethodSignature *original_sig;
4286 if (!mono_verifier_is_enabled_for_image (image))
4287 return TRUE;
4289 original_sig = mono_method_signature (method);
4290 if (original_sig->call_convention == MONO_CALL_VARARG) {
4291 if (original_sig->hasthis != signature->hasthis)
4292 return FALSE;
4293 if (original_sig->call_convention != signature->call_convention)
4294 return FALSE;
4295 if (original_sig->explicit_this != signature->explicit_this)
4296 return FALSE;
4297 if (original_sig->pinvoke != signature->pinvoke)
4298 return FALSE;
4299 if (original_sig->sentinelpos != signature->sentinelpos)
4300 return FALSE;
4301 } else if (!mono_metadata_signature_equal (signature, original_sig)) {
4302 return FALSE;
4305 return TRUE;
4308 gboolean
4309 mono_verifier_verify_typeref_row (MonoImage *image, guint32 row, MonoError *error)
4311 MonoTableInfo *table = &image->tables [MONO_TABLE_TYPEREF];
4312 guint32 data [MONO_TYPEREF_SIZE];
4314 error_init (error);
4316 if (!mono_verifier_is_enabled_for_image (image))
4317 return TRUE;
4319 if (row >= table->rows) {
4320 mono_error_set_bad_image (error, image, "Invalid typeref row %d - table has %d rows", row, table->rows);
4321 return FALSE;
4324 mono_metadata_decode_row (table, row, data, MONO_TYPEREF_SIZE);
4325 if (!is_valid_coded_index_with_image (image, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE])) {
4326 mono_error_set_bad_image (error, image, "Invalid typeref row %d coded index 0x%08x", row, data [MONO_TYPEREF_SCOPE]);
4327 return FALSE;
4330 if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE])) {
4331 mono_error_set_bad_image (error, image, "The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", row);
4332 return FALSE;
4335 if (!data [MONO_TYPEREF_NAME] || !is_valid_string_full_with_image (image, data [MONO_TYPEREF_NAME], FALSE)) {
4336 mono_error_set_bad_image (error, image, "Invalid typeref row %d name token 0x%08x", row, data [MONO_TYPEREF_NAME]);
4337 return FALSE;
4340 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_string_full_with_image (image, data [MONO_TYPEREF_NAMESPACE], FALSE)) {
4341 mono_error_set_bad_image (error, image, "Invalid typeref row %d namespace token 0x%08x", row, data [MONO_TYPEREF_NAMESPACE]);
4342 return FALSE;
4345 return TRUE;
4348 /*Perform additional verification including metadata ones*/
4349 gboolean
4350 mono_verifier_verify_methodimpl_row (MonoImage *image, guint32 row, MonoError *error)
4352 MonoMethod *declaration, *body;
4353 MonoMethodSignature *body_sig, *decl_sig;
4354 MonoTableInfo *table = &image->tables [MONO_TABLE_METHODIMPL];
4355 guint32 data [MONO_METHODIMPL_SIZE];
4357 error_init (error);
4359 if (!mono_verifier_is_enabled_for_image (image))
4360 return TRUE;
4362 if (row >= table->rows) {
4363 mono_error_set_bad_image (error, image, "Invalid methodimpl row %d - table has %d rows", row, table->rows);
4364 return FALSE;
4367 mono_metadata_decode_row (table, row, data, MONO_METHODIMPL_SIZE);
4369 body = method_from_method_def_or_ref (image, data [MONO_METHODIMPL_BODY], NULL, error);
4370 if (!body)
4371 return FALSE;
4373 declaration = method_from_method_def_or_ref (image, data [MONO_METHODIMPL_DECLARATION], NULL, error);
4374 if (!declaration)
4375 return FALSE;
4377 /* FIXME
4378 mono_class_setup_supertypes (class);
4379 if (!mono_class_has_parent (class, body->klass)) {
4380 mono_error_set_bad_image (error, image, "Invalid methodimpl body doesn't belong to parent for row %x", row);
4381 return FALSE;
4384 if (!(body_sig = mono_method_signature_checked (body, error))) {
4385 return FALSE;
4388 if (!(decl_sig = mono_method_signature_checked (declaration, error))) {
4389 return FALSE;
4392 if (!mono_verifier_is_signature_compatible (decl_sig, body_sig)) {
4393 mono_error_set_bad_image (error, image, "Invalid methodimpl body signature not compatible with declaration row %x", row);
4394 return FALSE;
4397 return TRUE;
4400 #else
4401 gboolean
4402 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
4404 return TRUE;
4407 gboolean
4408 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
4410 return TRUE;
4413 gboolean
4414 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
4416 return TRUE;
4419 gboolean
4420 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
4422 return TRUE;
4425 gboolean
4426 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4428 return TRUE;
4431 gboolean
4432 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
4434 return TRUE;
4437 gboolean
4438 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, MonoError *error)
4440 error_init (error);
4441 return TRUE;
4444 gboolean
4445 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
4447 return TRUE;
4450 gboolean
4451 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
4453 return TRUE;
4456 gboolean
4457 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
4459 return TRUE;
4462 gboolean
4463 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
4465 return TRUE;
4468 gboolean
4469 mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, GSList **error_list)
4471 return TRUE;
4474 gboolean
4475 mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, GSList **error_list)
4477 return TRUE;
4480 gboolean
4481 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
4483 return TRUE;
4487 gboolean
4488 mono_verifier_verify_typeref_row (MonoImage *image, guint32 row, MonoError *error)
4490 error_init (error);
4491 return TRUE;
4494 gboolean
4495 mono_verifier_verify_methodimpl_row (MonoImage *image, guint32 row, MonoError *error)
4497 error_init (error);
4498 return TRUE;
4501 gboolean
4502 mono_verifier_verify_memberref_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
4504 return TRUE;
4507 gboolean
4508 mono_verifier_verify_memberref_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4510 return TRUE;
4513 #endif /* DISABLE_VERIFIER */