2010-01-21 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / metadata / metadata-verify.c
blobe4ff0b7d53604d871e437e91ab25b44a539e7c79
1 /*
2 * metadata-verify.c: Metadata verfication support
4 * Author:
5 * Mono Project (http://www.mono-project.com)
7 * Copyright (C) 2005-2008 Novell, Inc. (http://www.novell.com)
8 */
9 #include <mono/metadata/object-internals.h>
10 #include <mono/metadata/verify.h>
11 #include <mono/metadata/verify-internals.h>
12 #include <mono/metadata/opcodes.h>
13 #include <mono/metadata/tabledefs.h>
14 #include <mono/metadata/reflection.h>
15 #include <mono/metadata/debug-helpers.h>
16 #include <mono/metadata/mono-endian.h>
17 #include <mono/metadata/metadata.h>
18 #include <mono/metadata/metadata-internals.h>
19 #include <mono/metadata/class-internals.h>
20 #include <mono/metadata/tokentype.h>
21 #include <mono/metadata/security-manager.h>
22 #include <mono/metadata/security-core-clr.h>
23 #include <mono/metadata/cil-coff.h>
24 #include <mono/metadata/attrdefs.h>
25 #include <mono/utils/strenc.h>
26 #include <string.h>
27 //#include <signal.h>
28 #include <ctype.h>
30 #ifndef DISABLE_VERIFIER
32 TODO add fail fast mode
33 TODO add PE32+ support
34 TODO verify the entry point RVA and content.
35 TODO load_section_table and load_data_directories must take PE32+ into account
36 TODO add section relocation support
37 TODO verify the relocation table, since we really don't use, no need so far.
38 TODO do full PECOFF resources verification
39 TODO verify in the CLI header entry point and resources
40 TODO implement null token typeref validation
41 TODO verify table wide invariants for typedef (sorting and uniqueness)
42 TODO implement proper authenticode data directory validation
43 TODO verify properties that require multiple tables to be valid
44 FIXME use subtraction based bounds checking to avoid overflows
45 FIXME get rid of metadata_streams and other fields from VerifyContext
48 #ifdef MONO_VERIFIER_DEBUG
49 #define VERIFIER_DEBUG(code) do { code; } while (0)
50 #else
51 #define VERIFIER_DEBUG(code)
52 #endif
54 #define INVALID_OFFSET ((guint32)-1)
55 #define INVALID_ADDRESS 0xffffffff
57 enum {
58 STAGE_PE,
59 STAGE_CLI,
60 STAGE_TABLES
63 enum {
64 IMPORT_TABLE_IDX = 1,
65 RESOURCE_TABLE_IDX = 2,
66 CERTIFICATE_TABLE_IDX = 4,
67 RELOCATION_TABLE_IDX = 5,
68 IAT_IDX = 12,
69 CLI_HEADER_IDX = 14,
72 enum {
73 STRINGS_STREAM,
74 USER_STRINGS_STREAM,
75 BLOB_STREAM,
76 GUID_STREAM,
77 TILDE_STREAM
81 #define INVALID_TABLE (0xFF)
82 /*format: number of bits, number of tables, tables{n. tables} */
83 const static unsigned char coded_index_desc[] = {
84 #define TYPEDEF_OR_REF_DESC (0)
85 2, /*bits*/
86 3, /*tables*/
87 MONO_TABLE_TYPEDEF,
88 MONO_TABLE_TYPEREF,
89 MONO_TABLE_TYPESPEC,
91 #define HAS_CONSTANT_DESC (TYPEDEF_OR_REF_DESC + 5)
92 2, /*bits*/
93 3, /*tables*/
94 MONO_TABLE_FIELD,
95 MONO_TABLE_PARAM,
96 MONO_TABLE_PROPERTY,
98 #define HAS_CATTR_DESC (HAS_CONSTANT_DESC + 5)
99 5, /*bits*/
100 20, /*tables*/
101 MONO_TABLE_METHOD,
102 MONO_TABLE_FIELD,
103 MONO_TABLE_TYPEREF,
104 MONO_TABLE_TYPEDEF,
105 MONO_TABLE_PARAM,
106 MONO_TABLE_INTERFACEIMPL,
107 MONO_TABLE_MEMBERREF,
108 MONO_TABLE_MODULE,
109 MONO_TABLE_DECLSECURITY,
110 MONO_TABLE_PROPERTY,
111 MONO_TABLE_EVENT,
112 MONO_TABLE_STANDALONESIG,
113 MONO_TABLE_MODULEREF,
114 MONO_TABLE_TYPESPEC,
115 MONO_TABLE_ASSEMBLY,
116 MONO_TABLE_ASSEMBLYREF,
117 MONO_TABLE_FILE,
118 MONO_TABLE_EXPORTEDTYPE,
119 MONO_TABLE_MANIFESTRESOURCE,
120 MONO_TABLE_GENERICPARAM,
122 #define HAS_FIELD_MARSHAL_DESC (HAS_CATTR_DESC + 22)
123 1, /*bits*/
124 2, /*tables*/
125 MONO_TABLE_FIELD,
126 MONO_TABLE_PARAM,
128 #define HAS_DECL_SECURITY_DESC (HAS_FIELD_MARSHAL_DESC + 4)
129 2, /*bits*/
130 3, /*tables*/
131 MONO_TABLE_TYPEDEF,
132 MONO_TABLE_METHOD,
133 MONO_TABLE_ASSEMBLY,
135 #define MEMBERREF_PARENT_DESC (HAS_DECL_SECURITY_DESC + 5)
136 3, /*bits*/
137 5, /*tables*/
138 MONO_TABLE_TYPEDEF,
139 MONO_TABLE_TYPEREF,
140 MONO_TABLE_MODULE,
141 MONO_TABLE_METHOD,
142 MONO_TABLE_TYPESPEC,
144 #define HAS_SEMANTICS_DESC (MEMBERREF_PARENT_DESC + 7)
145 1, /*bits*/
146 2, /*tables*/
147 MONO_TABLE_EVENT,
148 MONO_TABLE_PROPERTY,
150 #define METHODDEF_OR_REF_DESC (HAS_SEMANTICS_DESC + 4)
151 1, /*bits*/
152 2, /*tables*/
153 MONO_TABLE_METHOD,
154 MONO_TABLE_MEMBERREF,
156 #define MEMBER_FORWARDED_DESC (METHODDEF_OR_REF_DESC + 4)
157 1, /*bits*/
158 2, /*tables*/
159 MONO_TABLE_FIELD,
160 MONO_TABLE_METHOD,
162 #define IMPLEMENTATION_DESC (MEMBER_FORWARDED_DESC + 4)
163 2, /*bits*/
164 3, /*tables*/
165 MONO_TABLE_FILE,
166 MONO_TABLE_ASSEMBLYREF,
167 MONO_TABLE_EXPORTEDTYPE,
169 #define CATTR_TYPE_DESC (IMPLEMENTATION_DESC + 5)
170 3, /*bits*/
171 5, /*tables*/
172 INVALID_TABLE,
173 INVALID_TABLE,
174 MONO_TABLE_METHOD,
175 MONO_TABLE_MEMBERREF,
176 INVALID_TABLE,
178 #define RES_SCOPE_DESC (CATTR_TYPE_DESC + 7)
179 2, /*bits*/
180 4, /*tables*/
181 MONO_TABLE_MODULE,
182 MONO_TABLE_MODULEREF,
183 MONO_TABLE_ASSEMBLYREF,
184 MONO_TABLE_TYPEREF,
186 #define TYPE_OR_METHODDEF_DESC (RES_SCOPE_DESC + 6)
187 1, /*bits*/
188 2, /*tables*/
189 MONO_TABLE_TYPEDEF,
190 MONO_TABLE_METHOD
193 typedef struct {
194 guint32 rva;
195 guint32 size;
196 guint32 translated_offset;
197 } DataDirectory;
199 typedef struct {
200 guint32 offset;
201 guint32 size;
202 } OffsetAndSize;
204 typedef struct {
205 guint32 baseRVA;
206 guint32 baseOffset;
207 guint32 size;
208 guint32 rellocationsRVA;
209 guint16 numberOfRelocations;
210 } SectionHeader;
212 typedef struct {
213 guint32 row_count;
214 guint32 row_size;
215 guint32 offset;
216 } TableInfo;
218 typedef struct {
219 const char *data;
220 guint32 size, token;
221 GSList *errors;
222 int valid;
223 MonoImage *image;
224 gboolean report_error;
225 gboolean report_warning;
226 int stage;
228 DataDirectory data_directories [16];
229 guint32 section_count;
230 SectionHeader *sections;
232 OffsetAndSize metadata_streams [5]; //offset from begin of the image
233 } VerifyContext;
235 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception) \
236 do { \
237 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
238 vinfo->info.status = __status; \
239 vinfo->info.message = ( __msg); \
240 vinfo->exception_type = (__exception); \
241 (__ctx)->errors = g_slist_prepend ((__ctx)->errors, vinfo); \
242 } while (0)
244 #define ADD_WARNING(__ctx, __msg) \
245 do { \
246 if ((__ctx)->report_warning) { \
247 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_WARNING, MONO_EXCEPTION_INVALID_PROGRAM); \
248 (__ctx)->valid = 0; \
249 return; \
251 } while (0)
253 #define ADD_ERROR_NO_RETURN(__ctx, __msg) \
254 do { \
255 if ((__ctx)->report_error) \
256 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
257 (__ctx)->valid = 0; \
258 } while (0)
260 #define ADD_ERROR(__ctx, __msg) \
261 do { \
262 if ((__ctx)->report_error) \
263 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
264 (__ctx)->valid = 0; \
265 return; \
266 } while (0)
268 #define FAIL(__ctx, __msg) \
269 do { \
270 if ((__ctx)->report_error) \
271 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
272 (__ctx)->valid = 0; \
273 return FALSE; \
274 } while (0)
276 #define CHECK_STATE() do { if (!ctx.valid) goto cleanup; } while (0)
278 #define CHECK_ERROR() do { if (!ctx->valid) return; } while (0)
280 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
281 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
283 #if SIZEOF_VOID_P == 4
284 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
285 #else
286 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
287 #endif
289 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
290 #define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
292 static const char *
293 dword_align (const char *ptr)
295 #if SIZEOF_VOID_P == 8
296 return (const char *) (((guint64) (ptr + 3)) & ~3);
297 #else
298 return (const char *) (((guint32) (ptr + 3)) & ~3);
299 #endif
302 static guint32
303 pe_signature_offset (VerifyContext *ctx)
305 return read32 (ctx->data + 0x3c);
308 static guint32
309 pe_header_offset (VerifyContext *ctx)
311 return read32 (ctx->data + 0x3c) + 4;
314 static gboolean
315 bounds_check_virtual_address (VerifyContext *ctx, guint32 rva, guint32 size)
317 int i;
319 if (rva + size < rva) //overflow
320 return FALSE;
322 if (ctx->stage > STAGE_PE) {
323 MonoCLIImageInfo *iinfo = ctx->image->image_info;
324 const int top = iinfo->cli_section_count;
325 MonoSectionTable *tables = iinfo->cli_section_tables;
326 int i;
328 for (i = 0; i < top; i++) {
329 guint32 base = tables->st_virtual_address;
330 guint32 end = base + tables->st_raw_data_size;
332 if (rva >= base && rva + size <= end)
333 return TRUE;
335 /*if ((addr >= tables->st_virtual_address) &&
336 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
338 return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
340 tables++;
342 return FALSE;
345 if (!ctx->sections)
346 return FALSE;
348 for (i = 0; i < ctx->section_count; ++i) {
349 guint32 base = ctx->sections [i].baseRVA;
350 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
351 if (rva >= base && rva + size <= end)
352 return TRUE;
354 return FALSE;
357 static gboolean
358 bounds_check_datadir (DataDirectory *dir, guint32 offset, guint32 size)
360 if (dir->translated_offset > offset)
361 return FALSE;
362 if (dir->size < size)
363 return FALSE;
364 return offset + size <= dir->translated_offset + dir->size;
367 static gboolean
368 bounds_check_offset (OffsetAndSize *off, guint32 offset, guint32 size)
370 if (off->offset > offset)
371 return FALSE;
373 if (off->size < size)
374 return FALSE;
376 return offset + size <= off->offset + off->size;
379 static guint32
380 translate_rva (VerifyContext *ctx, guint32 rva)
382 int i;
384 if (ctx->stage > STAGE_PE)
385 return mono_cli_rva_image_map (ctx->image, rva);
387 if (!ctx->sections)
388 return FALSE;
390 for (i = 0; i < ctx->section_count; ++i) {
391 guint32 base = ctx->sections [i].baseRVA;
392 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
393 if (rva >= base && rva <= end) {
394 guint32 res = (rva - base) + ctx->sections [i].baseOffset;
395 /* double check */
396 return res >= ctx->size ? INVALID_OFFSET : res;
400 return INVALID_OFFSET;
403 static void
404 verify_msdos_header (VerifyContext *ctx)
406 guint32 lfanew;
407 if (ctx->size < 128)
408 ADD_ERROR (ctx, g_strdup ("Not enough space for the MS-DOS header"));
409 if (ctx->data [0] != 0x4d || ctx->data [1] != 0x5a)
410 ADD_ERROR (ctx, g_strdup ("Invalid MS-DOS watermark"));
411 lfanew = pe_signature_offset (ctx);
412 if (lfanew > ctx->size - 4)
413 ADD_ERROR (ctx, g_strdup ("MS-DOS lfanew offset points to outside of the file"));
416 static void
417 verify_pe_header (VerifyContext *ctx)
419 guint32 offset = pe_signature_offset (ctx);
420 const char *pe_header = ctx->data + offset;
421 if (pe_header [0] != 'P' || pe_header [1] != 'E' ||pe_header [2] != 0 ||pe_header [3] != 0)
422 ADD_ERROR (ctx, g_strdup ("Invalid PE header watermark"));
423 pe_header += 4;
424 offset += 4;
426 if (offset > ctx->size - 20)
427 ADD_ERROR (ctx, g_strdup ("File with truncated pe header"));
428 if (read16 (pe_header) != 0x14c)
429 ADD_ERROR (ctx, g_strdup ("Invalid PE header Machine value"));
432 static void
433 verify_pe_optional_header (VerifyContext *ctx)
435 guint32 offset = pe_header_offset (ctx);
436 guint32 header_size, file_alignment;
437 const char *pe_header = ctx->data + offset;
438 const char *pe_optional_header = pe_header + 20;
440 header_size = read16 (pe_header + 16);
441 offset += 20;
443 if (header_size < 2) /*must be at least 2 or we won't be able to read magic*/
444 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
446 if (offset > ctx->size - header_size || header_size > ctx->size)
447 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
449 if (read16 (pe_optional_header) == 0x10b) {
450 if (header_size != 224)
451 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header size %d", header_size));
453 /* LAMESPEC MS plays around this value and ignore it during validation
454 if (read32 (pe_optional_header + 28) != 0x400000)
455 ADD_ERROR (ctx, g_strdup_printf ("Invalid Image base %x", read32 (pe_optional_header + 28)));*/
456 if (read32 (pe_optional_header + 32) != 0x2000)
457 ADD_ERROR (ctx, g_strdup_printf ("Invalid Section Aligmnent %x", read32 (pe_optional_header + 32)));
458 file_alignment = read32 (pe_optional_header + 36);
459 if (file_alignment != 0x200 && file_alignment != 0x1000)
460 ADD_ERROR (ctx, g_strdup_printf ("Invalid file Aligmnent %x", file_alignment));
461 /* All the junk in the middle is irrelevant, specially for mono. */
462 if (read32 (pe_optional_header + 92) > 0x10)
463 ADD_ERROR (ctx, g_strdup_printf ("Too many data directories %x", read32 (pe_optional_header + 92)));
464 } else {
465 if (read16 (pe_optional_header) == 0x20B)
466 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle PE32+"));
467 else
468 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header magic %d", read16 (pe_optional_header)));
472 static void
473 load_section_table (VerifyContext *ctx)
475 int i;
476 SectionHeader *sections;
477 guint32 offset = pe_header_offset (ctx);
478 const char *ptr = ctx->data + offset;
479 guint16 num_sections = ctx->section_count = read16 (ptr + 2);
481 offset += 244;/*FIXME, this constant is different under PE32+*/
482 ptr += 244;
484 if (num_sections * 40 > ctx->size - offset)
485 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
487 sections = ctx->sections = g_new0 (SectionHeader, num_sections);
488 for (i = 0; i < num_sections; ++i) {
489 sections [i].size = read32 (ptr + 8);
490 sections [i].baseRVA = read32 (ptr + 12);
491 sections [i].baseOffset = read32 (ptr + 20);
492 sections [i].rellocationsRVA = read32 (ptr + 24);
493 sections [i].numberOfRelocations = read16 (ptr + 32);
494 ptr += 40;
497 ptr = ctx->data + offset; /*reset it to the beggining*/
498 for (i = 0; i < num_sections; ++i) {
499 guint32 raw_size, flags;
500 if (sections [i].baseOffset == 0)
501 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with intialized data only"));
502 if (sections [i].baseOffset >= ctx->size)
503 ADD_ERROR (ctx, g_strdup_printf ("Invalid PointerToRawData %x points beyond EOF", sections [i].baseOffset));
504 if (sections [i].size > ctx->size - sections [i].baseOffset)
505 ADD_ERROR (ctx, g_strdup ("Invalid VirtualSize points beyond EOF"));
507 raw_size = read32 (ptr + 16);
508 if (raw_size < sections [i].size)
509 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with SizeOfRawData < VirtualSize"));
511 if (raw_size > ctx->size - sections [i].baseOffset)
512 ADD_ERROR (ctx, g_strdup_printf ("Invalid SizeOfRawData %x points beyond EOF", raw_size));
514 if (sections [i].rellocationsRVA || sections [i].numberOfRelocations)
515 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't handle section relocation"));
517 flags = read32 (ptr + 36);
518 /*TODO 0xFE0000E0 is all flags from cil-coff.h OR'd. Make it a less magical number*/
519 if (flags == 0 || (flags & ~0xFE0000E0) != 0)
520 ADD_ERROR (ctx, g_strdup_printf ("Invalid section flags %x", flags));
522 ptr += 40;
526 static gboolean
527 is_valid_data_directory (int i)
529 /*LAMESPEC 4 == certificate 6 == debug, MS uses both*/
530 return i == 1 || i == 2 || i == 5 || i == 12 || i == 14 || i == 4 || i == 6;
533 static void
534 load_data_directories (VerifyContext *ctx)
536 guint32 offset = pe_header_offset (ctx) + 116; /*FIXME, this constant is different under PE32+*/
537 const char *ptr = ctx->data + offset;
538 int i;
540 for (i = 0; i < 16; ++i) {
541 guint32 rva = read32 (ptr);
542 guint32 size = read32 (ptr + 4);
544 /*LAMESPEC the authenticode data directory format is different. We don't support CAS, so lets ignore for now.*/
545 if (i == CERTIFICATE_TABLE_IDX) {
546 ptr += 8;
547 continue;
549 if ((rva != 0 || size != 0) && !is_valid_data_directory (i))
550 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d", i));
552 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
553 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d rva/size pair %x/%x", i, rva, size));
555 ctx->data_directories [i].rva = rva;
556 ctx->data_directories [i].size = size;
557 ctx->data_directories [i].translated_offset = translate_rva (ctx, rva);
559 ptr += 8;
563 #define SIZE_OF_MSCOREE (sizeof ("mscoree.dll"))
565 #define SIZE_OF_CORMAIN (sizeof ("_CorExeMain"))
567 static void
568 verify_hint_name_table (VerifyContext *ctx, guint32 import_rva, const char *table_name)
570 const char *ptr;
571 guint32 hint_table_rva;
573 import_rva = translate_rva (ctx, import_rva);
574 g_assert (import_rva != INVALID_OFFSET);
576 hint_table_rva = read32 (ctx->data + import_rva);
577 if (!bounds_check_virtual_address (ctx, hint_table_rva, SIZE_OF_CORMAIN + 2))
578 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint/Name rva %d for %s", hint_table_rva, table_name));
580 hint_table_rva = translate_rva (ctx, hint_table_rva);
581 g_assert (hint_table_rva != INVALID_OFFSET);
582 ptr = ctx->data + hint_table_rva + 2;
584 if (memcmp ("_CorExeMain", ptr, SIZE_OF_CORMAIN) && memcmp ("_CorDllMain", ptr, SIZE_OF_CORMAIN)) {
585 char name[SIZE_OF_CORMAIN];
586 memcpy (name, ptr, SIZE_OF_CORMAIN);
587 name [SIZE_OF_CORMAIN - 1] = 0;
588 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint / Name: '%s'", name));
592 static void
593 verify_import_table (VerifyContext *ctx)
595 DataDirectory it = ctx->data_directories [IMPORT_TABLE_IDX];
596 guint32 offset = it.translated_offset;
597 const char *ptr = ctx->data + offset;
598 guint32 name_rva, ilt_rva, iat_rva;
600 g_assert (offset != INVALID_OFFSET);
602 if (it.size < 40)
603 ADD_ERROR (ctx, g_strdup_printf ("Import table size %d is smaller than 40", it.size));
605 ilt_rva = read32 (ptr);
606 if (ilt_rva && !bounds_check_virtual_address (ctx, ilt_rva, 8))
607 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Lookup Table rva %x", ilt_rva));
609 name_rva = read32 (ptr + 12);
610 if (name_rva && !bounds_check_virtual_address (ctx, name_rva, SIZE_OF_MSCOREE))
611 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name rva %x", name_rva));
613 iat_rva = read32 (ptr + 16);
614 if (iat_rva) {
615 if (!bounds_check_virtual_address (ctx, iat_rva, 8))
616 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Address Table rva %x", iat_rva));
618 if (iat_rva != ctx->data_directories [IAT_IDX].rva)
619 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));
622 if (name_rva) {
623 name_rva = translate_rva (ctx, name_rva);
624 g_assert (name_rva != INVALID_OFFSET);
625 ptr = ctx->data + name_rva;
627 if (memcmp ("mscoree.dll", ptr, SIZE_OF_MSCOREE)) {
628 char name[SIZE_OF_MSCOREE];
629 memcpy (name, ptr, SIZE_OF_MSCOREE);
630 name [SIZE_OF_MSCOREE - 1] = 0;
631 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name: '%s'", name));
635 if (ilt_rva) {
636 verify_hint_name_table (ctx, ilt_rva, "Import Lookup Table");
637 CHECK_ERROR ();
640 if (iat_rva)
641 verify_hint_name_table (ctx, iat_rva, "Import Address Table");
644 static void
645 verify_resources_table (VerifyContext *ctx)
647 DataDirectory it = ctx->data_directories [RESOURCE_TABLE_IDX];
648 guint32 offset;
649 guint16 named_entries, id_entries;
650 const char *ptr, *root, *end;
652 if (it.rva == 0)
653 return;
655 if (it.size < 16)
656 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));
658 offset = it.translated_offset;
659 root = ptr = ctx->data + offset;
660 end = root + it.size;
662 g_assert (offset != INVALID_OFFSET);
664 named_entries = read16 (ptr + 12);
665 id_entries = read16 (ptr + 14);
667 if ((named_entries + id_entries) * 8 + 16 > it.size)
668 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));
670 /* XXX at least one unmanaged resource is added due to a call to AssemblyBuilder::DefineVersionInfoResource ()
671 if (named_entries || id_entries)
672 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support full verification of PECOFF resources"));
676 /*----------nothing from here on can use data_directory---*/
678 static DataDirectory
679 get_data_dir (VerifyContext *ctx, int idx)
681 MonoCLIImageInfo *iinfo = ctx->image->image_info;
682 MonoPEDirEntry *entry= &iinfo->cli_header.datadir.pe_export_table;
683 DataDirectory res;
685 entry += idx;
686 res.rva = entry->rva;
687 res.size = entry->size;
688 res.translated_offset = translate_rva (ctx, res.rva);
689 return res;
692 static void
693 verify_cli_header (VerifyContext *ctx)
695 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
696 guint32 offset;
697 const char *ptr;
698 int i;
700 if (it.rva == 0)
701 ADD_ERROR (ctx, g_strdup_printf ("CLI header missing"));
703 if (it.size != 72)
704 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size in data directory %d must be 72", it.size));
706 offset = it.translated_offset;
707 ptr = ctx->data + offset;
709 g_assert (offset != INVALID_OFFSET);
711 if (read16 (ptr) != 72)
712 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size %d must be 72", read16 (ptr)));
714 if (!bounds_check_virtual_address (ctx, read32 (ptr + 8), read32 (ptr + 12)))
715 ADD_ERROR (ctx, g_strdup_printf ("Invalid medatata section rva/size pair %x/%x", read32 (ptr + 8), read32 (ptr + 12)));
718 if (!read32 (ptr + 8) || !read32 (ptr + 12))
719 ADD_ERROR (ctx, g_strdup_printf ("Missing medatata section in the CLI header"));
721 if ((read32 (ptr + 16) & ~0x0001000B) != 0)
722 ADD_ERROR (ctx, g_strdup_printf ("Invalid CLI header flags"));
724 ptr += 24;
725 for (i = 0; i < 6; ++i) {
726 guint32 rva = read32 (ptr);
727 guint32 size = read32 (ptr + 4);
729 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
730 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli section %i rva/size pair %x/%x", i, rva, size));
732 ptr += 8;
734 if (rva && i > 1)
735 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't support cli header section %d", i));
739 static guint32
740 pad4 (guint32 offset)
742 if (offset & 0x3) //pad to the next 4 byte boundary
743 offset = (offset & ~0x3) + 4;
744 return offset;
747 static void
748 verify_metadata_header (VerifyContext *ctx)
750 int i;
751 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
752 guint32 offset, section_count;
753 const char *ptr;
755 offset = it.translated_offset;
756 ptr = ctx->data + offset;
757 g_assert (offset != INVALID_OFFSET);
759 //build a directory entry for the metadata root
760 ptr += 8;
761 it.rva = read32 (ptr);
762 ptr += 4;
763 it.size = read32 (ptr);
764 it.translated_offset = offset = translate_rva (ctx, it.rva);
766 ptr = ctx->data + offset;
767 g_assert (offset != INVALID_OFFSET);
769 if (it.size < 20)
770 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small %d (at least 20 bytes required for initial decoding)", it.size));
772 if (read32 (ptr) != 0x424A5342)
773 ADD_ERROR (ctx, g_strdup_printf ("Invalid metadata signature, expected 0x424A5342 but got %08x", read32 (ptr)));
775 offset = pad4 (offset + 16 + read32 (ptr + 12));
777 if (!bounds_check_datadir (&it, offset, 4))
778 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));
780 ptr = ctx->data + offset; //move to streams header
782 section_count = read16 (ptr + 2);
783 if (section_count < 3)
784 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section must have at least 3 streams (#~, #GUID and #Blob"));
786 ptr += 4;
787 offset += 4;
789 for (i = 0; i < section_count; ++i) {
790 guint32 stream_off, stream_size;
791 int string_size, stream_idx;
793 if (!bounds_check_datadir (&it, offset, 8))
794 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));
796 stream_off = it.translated_offset + read32 (ptr);
797 stream_size = read32 (ptr + 4);
799 if (!bounds_check_datadir (&it, stream_off, stream_size))
800 ADD_ERROR (ctx, g_strdup_printf ("Invalid stream header %d offset/size pair %x/%x", 0, stream_off, stream_size));
802 ptr += 8;
803 offset += 8;
805 for (string_size = 0; string_size < 32; ++string_size) {
806 if (!bounds_check_datadir (&it, offset++, 1))
807 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small to decode stream header %d name", i));
808 if (!ptr [string_size])
809 break;
812 if (ptr [string_size])
813 ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d name larger than 32 bytes", i));
815 if (!strncmp ("#Strings", ptr, 9))
816 stream_idx = STRINGS_STREAM;
817 else if (!strncmp ("#US", ptr, 4))
818 stream_idx = USER_STRINGS_STREAM;
819 else if (!strncmp ("#Blob", ptr, 6))
820 stream_idx = BLOB_STREAM;
821 else if (!strncmp ("#GUID", ptr, 6))
822 stream_idx = GUID_STREAM;
823 else if (!strncmp ("#~", ptr, 3))
824 stream_idx = TILDE_STREAM;
825 else {
826 ADD_WARNING (ctx, g_strdup_printf ("Metadata stream header %d invalid name %s", i, ptr));
827 offset = pad4 (offset);
828 ptr = ctx->data + offset;
829 continue;
832 if (ctx->metadata_streams [stream_idx].offset != 0)
833 ADD_ERROR (ctx, g_strdup_printf ("Duplicated metadata stream header %s", ptr));
835 ctx->metadata_streams [stream_idx].offset = stream_off;
836 ctx->metadata_streams [stream_idx].size = stream_size;
838 offset = pad4 (offset);
839 ptr = ctx->data + offset;
842 if (!ctx->metadata_streams [TILDE_STREAM].size)
843 ADD_ERROR (ctx, g_strdup_printf ("Metadata #~ stream missing"));
844 if (!ctx->metadata_streams [GUID_STREAM].size)
845 ADD_ERROR (ctx, g_strdup_printf ("Metadata guid stream missing"));
846 if (!ctx->metadata_streams [BLOB_STREAM].size)
847 ADD_ERROR (ctx, g_strdup_printf ("Metadata blob stream missing"));
851 static void
852 verify_tables_schema (VerifyContext *ctx)
854 OffsetAndSize tables_area = ctx->metadata_streams [TILDE_STREAM];
855 unsigned offset = tables_area.offset;
856 const char *ptr = ctx->data + offset;
857 guint64 valid_tables;
858 guint32 count;
859 int i;
861 //printf ("tables_area size %d offset %x %s\n", tables_area.size, tables_area.offset, ctx->image->name);
862 if (tables_area.size < 24)
863 ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for initial decoding (requires 24 bytes)", tables_area.size));
865 //printf ("ptr %x %x\n", ptr[4], ptr[5]);
866 if (ptr [4] != 2 && ptr [4] != 1)
867 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata major version %d, expected 2", ptr [4]));
868 if (ptr [5] != 0)
869 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata minor version %d, expected 0", ptr [5]));
871 if ((ptr [6] & ~0x7) != 0)
872 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]));
874 valid_tables = read64 (ptr + 8);
875 count = 0;
876 for (i = 0; i < 64; ++i) {
877 if (!(valid_tables & ((guint64)1 << i)))
878 continue;
880 /*MS Extensions: 0x3 0x5 0x7 0x13 0x16
881 Unused: 0x1E 0x1F 0x2D-0x3F
882 We don't care about the MS extensions.*/
883 if (i == 0x3 || i == 0x5 || i == 0x7 || i == 0x13 || i == 0x16)
884 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support MS specific table %x", i));
885 if (i == 0x1E || i == 0x1F || i >= 0x2D)
886 ADD_ERROR (ctx, g_strdup_printf ("Invalid table %x", i));
887 ++count;
890 if (tables_area.size < 24 + count * 4)
891 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));
892 ptr += 24;
894 for (i = 0; i < 64; ++i) {
895 if (valid_tables & ((guint64)1 << i)) {
896 guint32 row_count = read32 (ptr);
897 if (row_count > (1 << 24) - 1)
898 ADD_ERROR (ctx, g_strdup_printf ("Invalid Table %d row count: %d. Mono only supports 16777215 rows", i, row_count));
899 ptr += 4;
904 /*----------nothing from here on can use data_directory or metadata_streams ---*/
906 static guint32
907 get_col_offset (VerifyContext *ctx, int table, int column)
909 guint32 bitfield = ctx->image->tables [table].size_bitfield;
910 guint32 offset = 0;
912 while (column-- > 0)
913 offset += mono_metadata_table_size (bitfield, column);
915 return offset;
918 static guint32
919 get_col_size (VerifyContext *ctx, int table, int column)
921 return mono_metadata_table_size (ctx->image->tables [table].size_bitfield, column);
924 static OffsetAndSize
925 get_metadata_stream (VerifyContext *ctx, MonoStreamHeader *header)
927 OffsetAndSize res;
928 res.offset = header->data - ctx->data;
929 res.size = header->size;
931 return res;
934 static gboolean
935 is_valid_string_full (VerifyContext *ctx, guint32 offset, gboolean allow_empty)
937 OffsetAndSize strings = get_metadata_stream (ctx, &ctx->image->heap_strings);
938 glong length;
939 const char *data = ctx->data + strings.offset;
941 if (offset >= strings.size)
942 return FALSE;
943 if (data + offset < data) //FIXME, use a generalized and smart unsigned add with overflow check and fix the whole thing
944 return FALSE;
946 if (!mono_utf8_validate_and_len_with_bounds (data + offset, strings.size - offset, &length, NULL))
947 return FALSE;
948 return allow_empty || length > 0;
951 static gboolean
952 is_valid_string (VerifyContext *ctx, guint32 offset)
954 return is_valid_string_full (ctx, offset, TRUE);
957 static gboolean
958 is_valid_non_empty_string (VerifyContext *ctx, guint32 offset)
960 return is_valid_string_full (ctx, offset, FALSE);
963 static gboolean
964 is_valid_guid (VerifyContext *ctx, guint32 offset)
966 OffsetAndSize guids = get_metadata_stream (ctx, &ctx->image->heap_guid);
967 return guids.size >= 8 && guids.size - 8 >= offset;
970 static guint32
971 get_coded_index_token (int token_kind, guint32 coded_token)
973 guint32 bits = coded_index_desc [token_kind];
974 return coded_token >> bits;
977 static guint32
978 get_coded_index_table (int kind, guint32 coded_token)
980 guint32 idx, bits = coded_index_desc [kind];
981 kind += 2;
982 idx = coded_token & ((1 << bits) - 1);
983 return coded_index_desc [kind + idx];
986 static guint32
987 make_coded_token (int kind, guint32 table, guint32 table_idx)
989 guint32 bits = coded_index_desc [kind++];
990 guint32 tables = coded_index_desc [kind++];
991 guint32 i;
992 for (i = 0; i < tables; ++i) {
993 if (coded_index_desc [kind++] == table)
994 return ((table_idx + 1) << bits) | i;
996 g_assert_not_reached ();
997 return -1;
1000 static gboolean
1001 is_valid_coded_index (VerifyContext *ctx, int token_kind, guint32 coded_token)
1003 guint32 bits = coded_index_desc [token_kind++];
1004 guint32 table_count = coded_index_desc [token_kind++];
1005 guint32 table = coded_token & ((1 << bits) - 1);
1006 guint32 token = coded_token >> bits;
1008 if (table >= table_count)
1009 return FALSE;
1011 /*token_kind points to the first table idx*/
1012 table = coded_index_desc [token_kind + table];
1014 if (table == INVALID_TABLE)
1015 return FALSE;
1016 return token <= ctx->image->tables [table].rows;
1019 typedef struct {
1020 guint32 token;
1021 guint32 col_size;
1022 guint32 col_offset;
1023 MonoTableInfo *table;
1024 } RowLocator;
1026 static int
1027 token_locator (const void *a, const void *b)
1029 RowLocator *loc = (RowLocator *)a;
1030 unsigned const char *row = (unsigned const char *)b;
1031 guint32 token = loc->col_size == 2 ? read16 (row + loc->col_offset) : read32 (row + loc->col_offset);
1033 VERIFIER_DEBUG ( printf ("\tfound token %x at idx %d\n", token, ((const char*)row - loc->table->base) / loc->table->row_size) );
1034 return (int)loc->token - (int)token;
1037 static int
1038 search_sorted_table (VerifyContext *ctx, int table, int column, guint32 coded_token)
1040 MonoTableInfo *tinfo = &ctx->image->tables [table];
1041 RowLocator locator;
1042 const char *res, *base;
1043 locator.token = coded_token;
1044 locator.col_offset = get_col_offset (ctx, table, column);
1045 locator.col_size = get_col_size (ctx, table, column);
1046 locator.table = tinfo;
1048 base = tinfo->base;
1050 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) );
1051 res = bsearch (&locator, base, tinfo->rows, tinfo->row_size, token_locator);
1052 if (!res)
1053 return -1;
1055 return (res - base) / tinfo->row_size;
1058 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1059 static const char*
1060 get_string_ptr (VerifyContext *ctx, guint offset)
1062 return ctx->image->heap_strings.data + offset;
1065 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1066 static int
1067 string_cmp (VerifyContext *ctx, const char *str, guint offset)
1069 if (offset == 0)
1070 return strcmp (str, "");
1072 return strcmp (str, get_string_ptr (ctx, offset));
1075 static gboolean
1076 mono_verifier_is_corlib (MonoImage *image)
1078 gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ?
1079 TRUE : mono_security_core_clr_is_platform_image (image);
1081 return trusted_location && image->module_name && !strcmp ("mscorlib.dll", image->module_name);
1084 static gboolean
1085 typedef_is_system_object (VerifyContext *ctx, guint32 *data)
1087 return mono_verifier_is_corlib (ctx->image) && !string_cmp (ctx, "System", data [MONO_TYPEDEF_NAMESPACE]) && !string_cmp (ctx, "Object", data [MONO_TYPEDEF_NAME]);
1090 static gboolean
1091 decode_value (const char *_ptr, unsigned available, unsigned *value, unsigned *size)
1093 unsigned char b;
1094 const unsigned char *ptr = (const unsigned char *)_ptr;
1096 if (!available)
1097 return FALSE;
1099 b = *ptr;
1100 *value = *size = 0;
1102 if ((b & 0x80) == 0) {
1103 *size = 1;
1104 *value = b;
1105 } else if ((b & 0x40) == 0) {
1106 if (available < 2)
1107 return FALSE;
1108 *size = 2;
1109 *value = ((b & 0x3f) << 8 | ptr [1]);
1110 } else {
1111 if (available < 4)
1112 return FALSE;
1113 *size = 4;
1114 *value = ((b & 0x1f) << 24) |
1115 (ptr [1] << 16) |
1116 (ptr [2] << 8) |
1117 ptr [3];
1120 return TRUE;
1123 static gboolean
1124 decode_signature_header (VerifyContext *ctx, guint32 offset, int *size, const char **first_byte)
1126 MonoStreamHeader blob = ctx->image->heap_blob;
1127 guint32 value, enc_size;
1129 if (offset >= blob.size)
1130 return FALSE;
1132 if (!decode_value (blob.data + offset, blob.size - offset, &value, &enc_size))
1133 return FALSE;
1135 if (offset + enc_size + value < offset)
1136 return FALSE;
1138 if (offset + enc_size + value > blob.size)
1139 return FALSE;
1141 *size = value;
1142 *first_byte = blob.data + offset + enc_size;
1143 return TRUE;
1146 static gboolean
1147 safe_read (const char **_ptr, const char *limit, unsigned *dest, int size)
1149 const char *ptr = *_ptr;
1150 if (ptr + size > limit)
1151 return FALSE;
1152 switch (size) {
1153 case 1:
1154 *dest = *((guint8*)ptr);
1155 ++ptr;
1156 break;
1157 case 2:
1158 *dest = read16 (ptr);
1159 ptr += 2;
1160 break;
1161 case 4:
1162 *dest = read32 (ptr);
1163 ptr += 4;
1164 break;
1166 *_ptr = ptr;
1167 return TRUE;
1170 static gboolean
1171 safe_read_compressed_int (const char **_ptr, const char *limit, unsigned *dest)
1173 unsigned size = 0;
1174 const char *ptr = *_ptr;
1175 gboolean res = decode_value (ptr, limit - ptr, dest, &size);
1176 *_ptr = ptr + size;
1177 return res;
1180 #define safe_read8(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 1)
1181 #define safe_read_cint(VAR, PTR, LIMIT) safe_read_compressed_int (&PTR, LIMIT, &VAR)
1182 #define safe_read16(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 2)
1183 #define safe_read32(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 4)
1185 static gboolean
1186 parse_type (VerifyContext *ctx, const char **_ptr, const char *end);
1188 static gboolean
1189 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged);
1191 static gboolean
1192 parse_custom_mods (VerifyContext *ctx, const char **_ptr, const char *end)
1194 const char *ptr = *_ptr;
1195 unsigned type = 0;
1196 unsigned token = 0;
1198 while (TRUE) {
1199 if (!safe_read8 (type, ptr, end))
1200 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the type"));
1202 if (type != MONO_TYPE_CMOD_REQD && type != MONO_TYPE_CMOD_OPT) {
1203 --ptr;
1204 break;
1207 if (!safe_read_cint (token, ptr, end))
1208 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the token"));
1210 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1211 FAIL (ctx, g_strdup_printf ("CustomMod: invalid TypeDefOrRef token %x", token));
1214 *_ptr = ptr;
1215 return TRUE;
1218 static gboolean
1219 parse_array_shape (VerifyContext *ctx, const char **_ptr, const char *end)
1221 const char *ptr = *_ptr;
1222 unsigned val = 0;
1223 unsigned size, num, i;
1225 if (!safe_read8 (val, ptr, end))
1226 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for Rank"));
1228 if (val == 0)
1229 FAIL (ctx, g_strdup ("ArrayShape: Invalid shape with zero Rank"));
1231 if (!safe_read_cint (size, ptr, end))
1232 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumSizes"));
1234 for (i = 0; i < size; ++i) {
1235 if (!safe_read_cint (num, ptr, end))
1236 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for Size of rank %d", i + 1));
1239 if (!safe_read_cint (size, ptr, end))
1240 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumLoBounds"));
1242 for (i = 0; i < size; ++i) {
1243 if (!safe_read_cint (num, ptr, end))
1244 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for LoBound of rank %d", i + 1));
1247 *_ptr = ptr;
1248 return TRUE;
1251 static gboolean
1252 parse_generic_inst (VerifyContext *ctx, const char **_ptr, const char *end)
1254 const char *ptr = *_ptr;
1255 unsigned type;
1256 unsigned count, token, i;
1258 if (!safe_read8 (type, ptr, end))
1259 FAIL (ctx, g_strdup ("GenericInst: Not enough room for kind"));
1261 if (type != MONO_TYPE_CLASS && type != MONO_TYPE_VALUETYPE)
1262 FAIL (ctx, g_strdup_printf ("GenericInst: Invalid GenericInst kind %x\n", type));
1264 if (!safe_read_cint (token, ptr, end))
1265 FAIL (ctx, g_strdup ("GenericInst: Not enough room for type token"));
1267 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1268 FAIL (ctx, g_strdup_printf ("GenericInst: invalid TypeDefOrRef token %x", token));
1270 if (ctx->token) {
1271 if (mono_metadata_token_index (ctx->token) == get_coded_index_token (TYPEDEF_OR_REF_DESC, token) &&
1272 mono_metadata_token_table (ctx->token) == get_coded_index_table (TYPEDEF_OR_REF_DESC, token))
1273 FAIL (ctx, g_strdup_printf ("Type: Recurside generic instance specification (%x). A type signature can't reference itself", ctx->token));
1276 if (!safe_read_cint (count, ptr, end))
1277 FAIL (ctx, g_strdup ("GenericInst: Not enough room for argument count"));
1279 if (count == 0)
1280 FAIL (ctx, g_strdup ("GenericInst: Zero arguments generic instance"));
1282 for (i = 0; i < count; ++i) {
1283 if (!parse_type (ctx, &ptr, end))
1284 FAIL (ctx, g_strdup_printf ("GenericInst: invalid generic argument %d", i + 1));
1286 *_ptr = ptr;
1287 return TRUE;
1290 static gboolean
1291 parse_type (VerifyContext *ctx, const char **_ptr, const char *end)
1293 const char *ptr = *_ptr;
1294 unsigned type;
1295 unsigned token = 0;
1297 if (!safe_read8 (type, ptr, end))
1298 FAIL (ctx, g_strdup ("Type: Not enough room for the type"));
1300 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_PTR) ||
1301 (type >= MONO_TYPE_VALUETYPE && type <= MONO_TYPE_GENERICINST) ||
1302 (type >= MONO_TYPE_I && type <= MONO_TYPE_U) ||
1303 (type >= MONO_TYPE_FNPTR && type <= MONO_TYPE_MVAR)))
1304 FAIL (ctx, g_strdup_printf ("Type: Invalid type kind %x\n", type));
1306 switch (type) {
1307 case MONO_TYPE_PTR:
1308 if (!parse_custom_mods (ctx, &ptr, end))
1309 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1311 if (!safe_read8 (type, ptr, end))
1312 FAIL (ctx, g_strdup ("Type: Not enough room to parse the pointer type"));
1314 if (type != MONO_TYPE_VOID) {
1315 --ptr;
1316 if (!parse_type (ctx, &ptr, end))
1317 FAIL (ctx, g_strdup ("Type: Could not parse pointer type"));
1319 break;
1321 case MONO_TYPE_VALUETYPE:
1322 case MONO_TYPE_CLASS:
1323 if (!safe_read_cint (token, ptr, end))
1324 FAIL (ctx, g_strdup ("Type: Not enough room for the type token"));
1326 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1327 FAIL (ctx, g_strdup_printf ("Type: invalid TypeDefOrRef token %x", token));
1328 if (ctx->token) {
1329 if (mono_metadata_token_index (ctx->token) == get_coded_index_token (TYPEDEF_OR_REF_DESC, token) &&
1330 mono_metadata_token_table (ctx->token) == get_coded_index_table (TYPEDEF_OR_REF_DESC, token))
1331 FAIL (ctx, g_strdup_printf ("Type: Recurside type specification (%x). A type signature can't reference itself", ctx->token));
1333 break;
1335 case MONO_TYPE_VAR:
1336 case MONO_TYPE_MVAR:
1337 if (!safe_read_cint (token, ptr, end))
1338 FAIL (ctx, g_strdup ("Type: Not enough room for to decode generic argument number"));
1339 break;
1341 case MONO_TYPE_ARRAY:
1342 if (!parse_type (ctx, &ptr, end))
1343 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1344 if (!parse_array_shape (ctx, &ptr, end))
1345 FAIL (ctx, g_strdup ("Type: Could not parse array shape"));
1346 break;
1348 case MONO_TYPE_GENERICINST:
1349 if (!parse_generic_inst (ctx, &ptr, end))
1350 FAIL (ctx, g_strdup ("Type: Could not parse generic inst"));
1351 break;
1353 case MONO_TYPE_FNPTR:
1354 if (!parse_method_signature (ctx, &ptr, end, TRUE, TRUE))
1355 FAIL (ctx, g_strdup ("Type: Could not parse method pointer signature"));
1356 break;
1358 case MONO_TYPE_SZARRAY:
1359 if (!parse_custom_mods (ctx, &ptr, end))
1360 FAIL (ctx, g_strdup ("Type: Failed to parse array element custom attr"));
1361 if (!parse_type (ctx, &ptr, end))
1362 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1363 break;
1365 *_ptr = ptr;
1366 return TRUE;
1369 static gboolean
1370 parse_return_type (VerifyContext *ctx, const char **_ptr, const char *end)
1372 const char *ptr;
1373 unsigned type = 0;
1375 if (!parse_custom_mods (ctx, _ptr, end))
1376 return FALSE;
1378 ptr = *_ptr;
1379 if (!safe_read8 (type, ptr, end))
1380 FAIL (ctx, g_strdup ("ReturnType: Not enough room for the type"));
1382 if (type == MONO_TYPE_VOID || type == MONO_TYPE_TYPEDBYREF) {
1383 *_ptr = ptr;
1384 return TRUE;
1387 //it's a byref, update the cursor ptr
1388 if (type == MONO_TYPE_BYREF)
1389 *_ptr = ptr;
1391 return parse_type (ctx, _ptr, end);
1394 static gboolean
1395 parse_param (VerifyContext *ctx, const char **_ptr, const char *end)
1397 const char *ptr;
1398 unsigned type = 0;
1400 if (!parse_custom_mods (ctx, _ptr, end))
1401 return FALSE;
1403 ptr = *_ptr;
1404 if (!safe_read8 (type, ptr, end))
1405 FAIL (ctx, g_strdup ("Param: Not enough room for the type"));
1407 if (type == MONO_TYPE_TYPEDBYREF) {
1408 *_ptr = ptr;
1409 return TRUE;
1412 //it's a byref, update the cursor ptr
1413 if (type == MONO_TYPE_BYREF)
1414 *_ptr = ptr;
1416 return parse_type (ctx, _ptr, end);
1419 static gboolean
1420 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged)
1422 unsigned cconv = 0;
1423 unsigned param_count = 0, gparam_count = 0, type = 0, i;
1424 const char *ptr = *_ptr;
1425 gboolean saw_sentinel = FALSE;
1427 if (!safe_read8 (cconv, ptr, end))
1428 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the call conv"));
1430 if (cconv & 0x80)
1431 FAIL (ctx, g_strdup ("MethodSig: CallConv has 0x80 set"));
1433 if (allow_unmanaged) {
1434 if ((cconv & 0x0F) > MONO_CALL_VARARG)
1435 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not valid, it's %x", cconv & 0x0F));
1436 } else if ((cconv & 0x0F) != MONO_CALL_DEFAULT && (cconv & 0x0F) != MONO_CALL_VARARG)
1437 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not Default or Vararg, it's %x", cconv & 0x0F));
1439 if ((cconv & 0x10) && !safe_read_cint (gparam_count, ptr, end))
1440 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the generic param count"));
1442 if ((cconv & 0x10) && gparam_count == 0)
1443 FAIL (ctx, g_strdup ("MethodSig: Signature with generics but zero arity"));
1445 if (allow_unmanaged && (cconv & 0x10))
1446 FAIL (ctx, g_strdup ("MethodSig: Standalone signature with generic params"));
1448 if (!safe_read_cint (param_count, ptr, end))
1449 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the param count"));
1451 if (!parse_return_type (ctx, &ptr, end))
1452 FAIL (ctx, g_strdup ("MethodSig: Error parsing return type"));
1454 for (i = 0; i < param_count; ++i) {
1455 if (allow_sentinel) {
1456 if (!safe_read8 (type, ptr, end))
1457 FAIL (ctx, g_strdup_printf ("MethodSig: Not enough room for param %d type", i));
1459 if (type == MONO_TYPE_SENTINEL) {
1460 if ((cconv & 0x0F) != MONO_CALL_VARARG)
1461 FAIL (ctx, g_strdup ("MethodSig: Found sentinel but signature is not vararg"));
1463 if (saw_sentinel)
1464 FAIL (ctx, g_strdup ("MethodSig: More than one sentinel type"));
1466 saw_sentinel = TRUE;
1467 } else {
1468 --ptr;
1472 if (!parse_param (ctx, &ptr, end))
1473 FAIL (ctx, g_strdup_printf ("MethodSig: Error parsing arg %d", i));
1476 *_ptr = ptr;
1477 return TRUE;
1480 static gboolean
1481 parse_property_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1483 unsigned sig = 0;
1484 unsigned param_count = 0, i;
1485 const char *ptr = *_ptr;
1487 if (!safe_read8 (sig, ptr, end))
1488 FAIL (ctx, g_strdup ("PropertySig: Not enough room for signature"));
1490 if (sig != 0x08 && sig != 0x28)
1491 FAIL (ctx, g_strdup_printf ("PropertySig: Signature is not 0x28 or 0x08: %x", sig));
1493 if (!safe_read_cint (param_count, ptr, end))
1494 FAIL (ctx, g_strdup ("PropertySig: Not enough room for the param count"));
1496 if (!parse_custom_mods (ctx, &ptr, end))
1497 return FALSE;
1499 if (!parse_type (ctx, &ptr, end))
1500 FAIL (ctx, g_strdup ("PropertySig: Could not parse property type"));
1502 for (i = 0; i < param_count; ++i) {
1503 if (!parse_type (ctx, &ptr, end))
1504 FAIL (ctx, g_strdup_printf ("PropertySig: Error parsing arg %d", i));
1507 *_ptr = ptr;
1508 return TRUE;
1511 static gboolean
1512 parse_field (VerifyContext *ctx, const char **_ptr, const char *end)
1514 const char *ptr = *_ptr;
1515 unsigned signature = 0;
1517 if (!safe_read8 (signature, ptr, end))
1518 FAIL (ctx, g_strdup ("Field: Not enough room for field signature"));
1520 if (signature != 0x06)
1521 FAIL (ctx, g_strdup_printf ("Field: Invalid signature 0x%x, must be 6", signature));
1523 if (!parse_custom_mods (ctx, &ptr, end))
1524 return FALSE;
1526 if (safe_read8 (signature, ptr, end)) {
1527 if (signature != MONO_TYPE_BYREF)
1528 --ptr;
1530 *_ptr = ptr;
1532 return parse_type (ctx, _ptr, end);
1535 static gboolean
1536 parse_locals_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1538 unsigned sig = 0;
1539 unsigned locals_count = 0, i;
1540 const char *ptr = *_ptr;
1542 if (!safe_read8 (sig, ptr, end))
1543 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for signature"));
1545 if (sig != 0x07)
1546 FAIL (ctx, g_strdup_printf ("LocalsSig: Signature is not 0x28 or 0x08: %x", sig));
1548 if (!safe_read_cint (locals_count, ptr, end))
1549 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for the param count"));
1551 /* LAMEIMPL: MS sometimes generates empty local signatures and its verifier is ok with.
1552 if (locals_count == 0)
1553 FAIL (ctx, g_strdup ("LocalsSig: Signature with zero locals"));
1556 for (i = 0; i < locals_count; ++i) {
1557 if (!safe_read8 (sig, ptr, end))
1558 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1560 while (sig == MONO_TYPE_CMOD_REQD || sig == MONO_TYPE_CMOD_OPT || sig == MONO_TYPE_PINNED) {
1561 if (sig != MONO_TYPE_PINNED && !parse_custom_mods (ctx, &ptr, end))
1562 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1563 if (!safe_read8 (sig, ptr, end))
1564 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1567 if (sig == MONO_TYPE_BYREF) {
1568 if (!safe_read8 (sig, ptr, end))
1569 FAIL (ctx, g_strdup_printf ("Type: Not enough room for byref type for local %d", i));
1570 if (sig == MONO_TYPE_TYPEDBYREF)
1571 FAIL (ctx, g_strdup_printf ("Type: Invalid type typedref& for local %d", i));
1574 if (sig == MONO_TYPE_TYPEDBYREF)
1575 continue;
1577 --ptr;
1579 if (!parse_type (ctx, &ptr, end))
1580 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1583 *_ptr = ptr;
1584 return TRUE;
1587 static gboolean
1588 is_valid_field_signature (VerifyContext *ctx, guint32 offset)
1590 int size = 0;
1591 unsigned signature = 0;
1592 const char *ptr = NULL, *end;
1594 if (!decode_signature_header (ctx, offset, &size, &ptr))
1595 FAIL (ctx, g_strdup ("FieldSig: Could not decode signature header"));
1596 end = ptr + size;
1598 if (!safe_read8 (signature, ptr, end))
1599 FAIL (ctx, g_strdup ("FieldSig: Not enough room for the signature"));
1601 if (signature != 6)
1602 FAIL (ctx, g_strdup_printf ("FieldSig: Invalid signature %x", signature));
1603 --ptr;
1605 return parse_field (ctx, &ptr, end);
1608 static gboolean
1609 is_valid_method_signature (VerifyContext *ctx, guint32 offset)
1611 int size = 0;
1612 const char *ptr = NULL, *end;
1614 if (!decode_signature_header (ctx, offset, &size, &ptr))
1615 FAIL (ctx, g_strdup ("MethodSig: Could not decode signature header"));
1616 end = ptr + size;
1618 return parse_method_signature (ctx, &ptr, end, FALSE, FALSE);
1621 static gboolean
1622 is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
1624 int size = 0;
1625 unsigned signature = 0;
1626 const char *ptr = NULL, *end;
1628 if (!decode_signature_header (ctx, offset, &size, &ptr))
1629 FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
1630 end = ptr + size;
1632 if (!safe_read8 (signature, ptr, end))
1633 FAIL (ctx, g_strdup ("MemberRefSig: Not enough room for the call conv"));
1634 --ptr;
1636 if (signature == 0x06)
1637 return parse_field (ctx, &ptr, end);
1639 return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1642 static gboolean
1643 is_vald_cattr_blob (VerifyContext *ctx, guint32 offset)
1645 int size = 0;
1646 unsigned prolog = 0;
1647 const char *ptr = NULL, *end;
1649 if (!offset)
1650 return TRUE;
1652 if (!decode_signature_header (ctx, offset, &size, &ptr))
1653 FAIL (ctx, g_strdup ("CustomAttribute: Could not decode signature header"));
1654 end = ptr + size;
1656 if (!safe_read16 (prolog, ptr, end))
1657 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1659 if (prolog != 1)
1660 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1662 return TRUE;
1665 static gboolean
1666 is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
1668 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1669 //TODO do proper verification
1670 return blob.size >= 1 && blob.size - 1 >= offset;
1673 static gboolean
1674 is_valid_permission_set (VerifyContext *ctx, guint32 offset)
1676 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1677 //TODO do proper verification
1678 return blob.size >= 1 && blob.size - 1 >= offset;
1681 static gboolean
1682 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
1684 int size = 0;
1685 unsigned signature = 0;
1686 const char *ptr = NULL, *end;
1688 if (!decode_signature_header (ctx, offset, &size, &ptr))
1689 FAIL (ctx, g_strdup ("StandAloneSig: Could not decode signature header"));
1690 end = ptr + size;
1692 if (!safe_read8 (signature, ptr, end))
1693 FAIL (ctx, g_strdup ("StandAloneSig: Not enough room for the call conv"));
1695 --ptr;
1696 if (signature == 0x07)
1697 return parse_locals_signature (ctx, &ptr, end);
1698 return parse_method_signature (ctx, &ptr, end, TRUE, TRUE);
1701 static gboolean
1702 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
1704 int size = 0;
1705 const char *ptr = NULL, *end;
1707 if (!decode_signature_header (ctx, offset, &size, &ptr))
1708 FAIL (ctx, g_strdup ("PropertySig: Could not decode signature header"));
1709 end = ptr + size;
1711 return parse_property_signature (ctx, &ptr, end);
1714 static gboolean
1715 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
1717 int size = 0;
1718 const char *ptr = NULL, *end;
1719 unsigned type = 0;
1722 if (!decode_signature_header (ctx, offset, &size, &ptr))
1723 FAIL (ctx, g_strdup ("TypeSpec: Could not decode signature header"));
1724 end = ptr + size;
1726 if (!parse_custom_mods (ctx, &ptr, end))
1727 return FALSE;
1729 if (!safe_read8 (type, ptr, end))
1730 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for type"));
1732 if (type == MONO_TYPE_BYREF) {
1733 if (!safe_read8 (type, ptr, end))
1734 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for byref type"));
1735 if (type == MONO_TYPE_TYPEDBYREF)
1736 FAIL (ctx, g_strdup ("TypeSpec: Invalid type typedref&"));
1739 if (type == MONO_TYPE_TYPEDBYREF)
1740 return TRUE;
1742 --ptr;
1743 return parse_type (ctx, &ptr, end);
1746 static gboolean
1747 is_valid_methodspec_blob (VerifyContext *ctx, guint32 offset)
1749 int size = 0;
1750 const char *ptr = NULL, *end;
1751 unsigned type = 0;
1752 unsigned count = 0, i;
1754 if (!decode_signature_header (ctx, offset, &size, &ptr))
1755 FAIL (ctx, g_strdup ("MethodSpec: Could not decode signature header"));
1756 end = ptr + size;
1758 if (!safe_read8 (type, ptr, end))
1759 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for call convention"));
1761 if (type != 0x0A)
1762 FAIL (ctx, g_strdup_printf ("MethodSpec: Invalid call convention 0x%x, expected 0x0A", type));
1764 if (!safe_read_cint (count, ptr, end))
1765 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for parameter count"));
1767 if (!count)
1768 FAIL (ctx, g_strdup ("MethodSpec: Zero generic argument count"));
1770 for (i = 0; i < count; ++i) {
1771 if (!parse_type (ctx, &ptr, end))
1772 FAIL (ctx, g_strdup_printf ("MethodSpec: Could not parse parameter %d", i + 1));
1774 return TRUE;
1777 static gboolean
1778 is_valid_blob_object (VerifyContext *ctx, guint32 offset, guint32 minsize)
1780 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1781 guint32 entry_size, bytes;
1783 if (blob.size < offset)
1784 return FALSE;
1786 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1787 return FALSE;
1789 if (entry_size < minsize)
1790 return FALSE;
1792 if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
1793 return FALSE;
1794 entry_size += bytes;
1796 return !ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size);
1799 static gboolean
1800 is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
1802 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1803 guint32 size, entry_size, bytes;
1805 if (blob.size < offset)
1806 FAIL (ctx, g_strdup ("ContantValue: invalid offset"));
1808 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1809 FAIL (ctx, g_strdup ("ContantValue: not enough space to decode size"));
1811 if (type == MONO_TYPE_STRING) {
1812 //String is encoded as: compressed_int:len len *bytes
1813 offset += bytes;
1815 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size))
1816 FAIL (ctx, g_strdup_printf ("ContantValue: not enough space for string, required %d but got %d", entry_size * 2, blob.size - offset));
1818 return TRUE;
1821 switch (type) {
1822 case MONO_TYPE_BOOLEAN:
1823 case MONO_TYPE_I1:
1824 case MONO_TYPE_U1:
1825 size = 1;
1826 break;
1827 case MONO_TYPE_CHAR:
1828 case MONO_TYPE_I2:
1829 case MONO_TYPE_U2:
1830 size = 2;
1831 break;
1832 case MONO_TYPE_I4:
1833 case MONO_TYPE_U4:
1834 case MONO_TYPE_R4:
1835 case MONO_TYPE_CLASS:
1836 size = 4;
1837 break;
1839 case MONO_TYPE_I8:
1840 case MONO_TYPE_U8:
1841 case MONO_TYPE_R8:
1842 size = 8;
1843 break;
1844 default:
1845 g_assert_not_reached ();
1848 if (size != entry_size)
1849 FAIL (ctx, g_strdup_printf ("ContantValue: Expected size %d but got %d", size, entry_size));
1851 offset += bytes;
1853 if (ADD_IS_GREATER_OR_OVF (offset, size, blob.size))
1854 FAIL (ctx, g_strdup_printf ("ContantValue: Not enough room for constant, required %d but have %d", size, blob.size - offset));
1856 if (type == MONO_TYPE_CLASS && read32 (ctx->data + blob.offset + offset))
1857 FAIL (ctx, g_strdup_printf ("ContantValue: Type is class but value is not null"));
1858 return TRUE;
1861 #define FAT_HEADER_INVALID_FLAGS ~(0x3 | 0x8 | 0x10 | 0xF000)
1862 //only 0x01, 0x40 and 0x80 are allowed
1863 #define SECTION_HEADER_INVALID_FLAGS 0x3E
1865 static gboolean
1866 is_valid_method_header (VerifyContext *ctx, guint32 rva)
1868 unsigned local_vars_tok, code_size, offset = mono_cli_rva_image_map (ctx->image, rva);
1869 unsigned header = 0;
1870 unsigned fat_header = 0, size = 0, max_stack;
1871 const char *ptr = NULL, *end;
1873 if (offset == INVALID_ADDRESS)
1874 FAIL (ctx, g_strdup ("MethodHeader: Invalid RVA"));
1876 ptr = ctx->data + offset;
1877 end = ctx->data + ctx->size; /*no worries if it spawns multiple sections*/
1879 if (!safe_read8 (header, ptr, end))
1880 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for header"));
1882 switch (header & 0x3) {
1883 case 0:
1884 case 1:
1885 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid header type 0x%x", header & 0x3));
1886 case 2:
1887 header >>= 2;
1888 if (ADDP_IS_GREATER_OR_OVF (ptr, header, end))
1889 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for method body. Required %d, but only %d is available", header, (int)(end - ptr)));
1890 return TRUE;
1892 //FAT HEADER
1893 --ptr;
1894 if (!safe_read16 (fat_header, ptr, end))
1895 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for fat header"));
1897 size = (fat_header >> 12) & 0xF;
1898 if (size != 3)
1899 FAIL (ctx, g_strdup ("MethodHeader: header size must be 3"));
1901 if (!safe_read16 (max_stack, ptr, end))
1902 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for max stack"));
1904 if (!safe_read32 (code_size, ptr, end))
1905 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for code size"));
1907 if (!safe_read32 (local_vars_tok, ptr, end))
1908 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for local vars tok"));
1910 if (local_vars_tok) {
1911 if (((local_vars_tok >> 24) & 0xFF) != 0x11)
1912 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature table 0x%x", ((local_vars_tok >> 24) & 0xFF)));
1913 if ((local_vars_tok & 0xFFFFFF) > ctx->image->tables [MONO_TABLE_STANDALONESIG].rows)
1914 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature points to invalid row 0x%x", local_vars_tok & 0xFFFFFF));
1917 if (fat_header & FAT_HEADER_INVALID_FLAGS)
1918 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid fat signature flags %x", fat_header & FAT_HEADER_INVALID_FLAGS));
1920 if (ADDP_IS_GREATER_OR_OVF (ptr, code_size, end))
1921 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for code %d", code_size));
1923 if (!(fat_header & 0x08))
1924 return TRUE;
1926 ptr += code_size;
1928 do {
1929 unsigned section_header = 0, section_size = 0;
1930 gboolean is_fat;
1932 ptr = dword_align (ptr);
1933 if (!safe_read32 (section_header, ptr, end))
1934 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for data section header"));
1936 if (section_header & SECTION_HEADER_INVALID_FLAGS)
1937 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section header flags 0x%x", section_header & SECTION_HEADER_INVALID_FLAGS));
1939 is_fat = (section_header & METHOD_HEADER_SECTION_FAT_FORMAT) != 0;
1940 section_size = (section_header >> 8) & (is_fat ? 0xFFFFFF : 0xFF);
1942 if (section_size < 4)
1943 FAIL (ctx, g_strdup_printf ("MethodHeader: Section size too small"));
1945 if (ADDP_IS_GREATER_OR_OVF (ptr, section_size - 4, end)) /*must be section_size -4 as ptr was incremented by safe_read32*/
1946 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section content %d", section_size));
1948 if (section_header & METHOD_HEADER_SECTION_EHTABLE) {
1949 guint32 i, clauses = section_size / (is_fat ? 24 : 12);
1951 LAMEIMPL: MS emits section_size without accounting for header size.
1952 Mono does as the spec says. section_size is header + section
1953 MS's peverify happily accepts both.
1955 if ((clauses * (is_fat ? 24 : 12) != section_size) && (clauses * (is_fat ? 24 : 12) + 4 != section_size))
1956 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)));
1958 /* only verify the class token is verified as the rest is done by the IL verifier*/
1959 for (i = 0; i < clauses; ++i) {
1960 unsigned flags = *(unsigned char*)ptr;
1961 unsigned class_token = 0;
1962 ptr += (is_fat ? 20 : 8);
1963 if (!safe_read32 (class_token, ptr, end))
1964 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section %d", i));
1965 if (flags == MONO_EXCEPTION_CLAUSE_NONE && class_token) {
1966 guint table = mono_metadata_token_table (class_token);
1967 if (table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPESPEC)
1968 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token table %x", i, table));
1969 if (mono_metadata_token_index (class_token) > ctx->image->tables [table].rows)
1970 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token index %x", i, mono_metadata_token_index (class_token)));
1975 if (!(section_header & METHOD_HEADER_SECTION_MORE_SECTS))
1976 break;
1977 } while (1);
1978 return TRUE;
1981 static void
1982 verify_module_table (VerifyContext *ctx)
1984 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
1985 guint32 data [MONO_MODULE_SIZE];
1987 if (table->rows != 1)
1988 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
1990 mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
1992 if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
1993 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
1995 if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
1996 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
1998 if (data [MONO_MODULE_ENC] != 0)
1999 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
2001 if (data [MONO_MODULE_ENCBASE] != 0)
2002 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
2005 static void
2006 verify_typeref_table (VerifyContext *ctx)
2008 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
2009 guint32 data [MONO_TYPEREF_SIZE];
2010 int i;
2012 for (i = 0; i < table->rows; ++i) {
2013 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
2014 if (!is_valid_coded_index (ctx, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
2015 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d coded index 0x%08x", i, data [MONO_TYPEREF_SCOPE]));
2017 if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
2018 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", i));
2020 if (!data [MONO_TYPEREF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAME]))
2021 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d name token 0x%08x", i, data [MONO_TYPEREF_NAME]));
2023 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
2024 ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d namespace token 0x%08x", i, data [MONO_TYPEREF_NAMESPACE]));
2028 /*bits 9,11,14,15,19,21,24-31 */
2029 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 14) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
2030 static void
2031 verify_typedef_table (VerifyContext *ctx)
2033 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2034 guint32 data [MONO_TYPEDEF_SIZE];
2035 guint32 fieldlist = 1, methodlist = 1, visibility;
2036 int i;
2038 if (table->rows == 0)
2039 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2041 for (i = 0; i < table->rows; ++i) {
2042 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2043 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
2044 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
2046 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
2047 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
2049 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
2050 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2052 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
2053 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2055 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) && (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
2056 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
2058 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
2059 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
2061 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
2062 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
2064 if (data [MONO_TYPEDEF_EXTENDS] && !is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
2065 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
2067 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
2068 if ((visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) &&
2069 search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1) == -1)
2070 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d has nested visibility but no rows in the NestedClass table", i));
2072 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
2073 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
2075 if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2076 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
2078 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
2079 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));
2081 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
2082 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
2084 if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
2085 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
2087 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
2088 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));
2090 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
2091 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
2095 static void
2096 verify_typedef_table_full (VerifyContext *ctx)
2098 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2099 guint32 data [MONO_TYPEDEF_SIZE];
2100 int i;
2102 if (table->rows == 0)
2103 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2105 for (i = 0; i < table->rows; ++i) {
2106 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2108 if (i == 0) {
2109 if (data [MONO_TYPEDEF_EXTENDS] != 0)
2110 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
2111 continue;
2114 if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
2115 if (data [MONO_TYPEDEF_EXTENDS])
2116 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
2117 } else {
2118 gboolean is_sys_obj = typedef_is_system_object (ctx, data);
2119 gboolean has_parent = get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]) != 0;
2121 if (is_sys_obj) {
2122 if (has_parent)
2123 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
2124 } else {
2125 if (!has_parent) {
2126 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
2133 /*bits 3,11,14 */
2134 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
2135 static void
2136 verify_field_table (VerifyContext *ctx)
2138 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2139 guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
2140 int i;
2142 module_field_list = (guint32)-1;
2143 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2144 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2145 module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
2148 for (i = 0; i < table->rows; ++i) {
2149 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2150 flags = data [MONO_FIELD_FLAGS];
2152 if (flags & INVALID_FIELD_FLAG_BITS)
2153 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
2155 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)
2156 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
2158 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
2159 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
2161 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
2162 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
2164 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
2165 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
2167 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
2168 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
2169 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
2171 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
2172 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2173 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2175 if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
2176 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2177 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
2179 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
2180 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
2181 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2183 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
2184 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
2186 if (data [MONO_FIELD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_FIELD_SIGNATURE], 1))
2187 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature blob token 0x%x", i, data [MONO_FIELD_SIGNATURE]));
2189 //TODO verify contant flag
2191 if (i + 1 < module_field_list) {
2192 guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
2193 if (!(flags & FIELD_ATTRIBUTE_STATIC))
2194 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
2195 if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
2196 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
2201 static void
2202 verify_field_table_full (VerifyContext *ctx)
2204 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2205 guint32 data [MONO_FIELD_SIZE];
2206 int i;
2208 for (i = 0; i < table->rows; ++i) {
2209 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2211 if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
2212 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
2216 /*bits 6,8,9,10,11,13,14,15*/
2217 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 6) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
2218 static void
2219 verify_method_table (VerifyContext *ctx)
2221 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2222 guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
2223 guint32 paramlist = 1;
2224 gboolean is_ctor, is_cctor;
2225 const char *name;
2226 int i;
2228 module_method_list = (guint32)-1;
2229 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2230 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2231 module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
2234 for (i = 0; i < table->rows; ++i) {
2235 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2236 rva = data [MONO_METHOD_RVA];
2237 implflags = data [MONO_METHOD_IMPLFLAGS];
2238 flags = data [MONO_METHOD_FLAGS];
2239 access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
2240 code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
2243 if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
2244 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
2246 if (access == 0x7)
2247 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
2249 if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
2250 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
2252 name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
2253 is_ctor = !strcmp (".ctor", name);
2254 is_cctor = !strcmp (".cctor", name);
2256 if ((is_ctor || is_cctor) &&
2257 search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
2258 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
2260 if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
2261 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
2263 if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
2264 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
2265 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
2266 if (flags & METHOD_ATTRIBUTE_FINAL)
2267 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and Final", i));
2268 if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
2269 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
2272 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
2273 ADD_WARNING (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
2275 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
2276 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
2278 //XXX no checks against cas stuff 10,11,12,13)
2280 //TODO check iface with .ctor (15,16)
2282 if (i + 1 < module_method_list) {
2283 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2284 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
2285 if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
2286 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
2287 if (!(access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED || access == METHOD_ATTRIBUTE_PUBLIC || access == METHOD_ATTRIBUTE_PRIVATE))
2288 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public or Private", i));
2291 //TODO check valuetype for synchronized
2293 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
2294 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
2296 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
2297 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
2298 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
2299 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2300 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but not Static", i));
2303 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
2304 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2305 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
2307 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
2308 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
2310 //TODO check signature contents
2312 if (rva) {
2313 if (flags & METHOD_ATTRIBUTE_ABSTRACT)
2314 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", i));
2315 if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
2316 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
2317 } else {
2318 if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2319 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
2322 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2323 if (rva)
2324 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
2325 if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
2326 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
2328 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
2329 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
2331 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
2332 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
2334 if (data [MONO_METHOD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHOD_SIGNATURE], 1))
2335 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature blob token 0x%x", i, data [MONO_METHOD_SIGNATURE]));
2337 if (data [MONO_METHOD_PARAMLIST] == 0)
2338 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
2340 if (data [MONO_METHOD_PARAMLIST] < paramlist)
2341 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));
2343 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
2344 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
2346 paramlist = data [MONO_METHOD_PARAMLIST];
2351 static void
2352 verify_method_table_full (VerifyContext *ctx)
2354 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2355 guint32 data [MONO_METHOD_SIZE], rva;
2356 int i;
2358 for (i = 0; i < table->rows; ++i) {
2359 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2360 rva = data [MONO_METHOD_RVA];
2362 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
2363 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
2365 if (rva && !is_valid_method_header (ctx, rva))
2366 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
2370 static guint32
2371 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
2373 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2374 guint32 row = *current_method;
2375 guint32 paramlist, tmp;
2378 paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
2379 while (row < table->rows) {
2380 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
2381 if (tmp > paramlist) {
2382 *current_method = row;
2383 return tmp - paramlist;
2385 ++row;
2388 /*no more methods, all params apply to the last one*/
2389 *current_method = table->rows;
2390 return (guint32)-1;
2394 #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))
2395 static void
2396 verify_param_table (VerifyContext *ctx)
2398 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
2399 guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
2400 gboolean first_param = TRUE;
2401 int i;
2403 if (ctx->image->tables [MONO_TABLE_METHOD].rows == 0) {
2404 if (table->rows > 0)
2405 ADD_ERROR (ctx, g_strdup ("Param table has rows while the method table has zero"));
2406 return;
2409 remaining_params = get_next_param_count (ctx, &current_method);
2411 for (i = 0; i < table->rows; ++i) {
2412 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
2413 flags = data [MONO_PARAM_FLAGS];
2415 if (flags & INVALID_PARAM_FLAGS_BITS)
2416 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
2418 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
2419 if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
2420 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
2421 } else {
2422 if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
2423 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
2426 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)
2427 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
2429 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
2430 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
2432 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
2433 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
2435 first_param = FALSE;
2436 sequence = data [MONO_PARAM_SEQUENCE];
2437 if (--remaining_params == 0) {
2438 remaining_params = get_next_param_count (ctx, &current_method);
2439 first_param = TRUE;
2444 static void
2445 verify_interfaceimpl_table (VerifyContext *ctx)
2447 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
2448 guint32 data [MONO_INTERFACEIMPL_SIZE];
2449 int i;
2451 for (i = 0; i < table->rows; ++i) {
2452 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
2453 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2454 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2456 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2457 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
2459 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2460 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
2464 static void
2465 verify_memberref_table (VerifyContext *ctx)
2467 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2468 guint32 data [MONO_MEMBERREF_SIZE];
2469 int i;
2471 for (i = 0; i < table->rows; ++i) {
2472 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2474 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2475 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
2477 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2478 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
2480 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
2481 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
2483 if (data [MONO_MEMBERREF_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_MEMBERREF_SIGNATURE], 1))
2484 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d invalid signature blob token 0x%x", i, data [MONO_MEMBERREF_SIGNATURE]));
2489 static void
2490 verify_memberref_table_full (VerifyContext *ctx)
2492 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2493 guint32 data [MONO_MEMBERREF_SIZE];
2494 int i;
2496 for (i = 0; i < table->rows; ++i) {
2497 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2499 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
2500 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field 0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
2504 static void
2505 verify_constant_table (VerifyContext *ctx)
2507 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
2508 guint32 data [MONO_CONSTANT_SIZE], type;
2509 int i;
2511 for (i = 0; i < table->rows; ++i) {
2512 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
2513 type = data [MONO_CONSTANT_TYPE];
2515 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
2516 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
2518 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2519 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
2521 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2522 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
2524 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
2525 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
2529 static void
2530 verify_cattr_table (VerifyContext *ctx)
2532 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2533 guint32 data [MONO_CUSTOM_ATTR_SIZE];
2534 int i;
2536 for (i = 0; i < table->rows; ++i) {
2537 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2539 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
2540 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2542 if (!is_valid_coded_index (ctx, CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]))
2543 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2545 if (data [MONO_CUSTOM_ATTR_VALUE] && !is_valid_blob_object (ctx, data [MONO_CUSTOM_ATTR_VALUE], 0))
2546 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d invalid value blob 0x%x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2550 static void
2551 verify_cattr_table_full (VerifyContext *ctx)
2553 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2554 guint32 data [MONO_CUSTOM_ATTR_SIZE];
2555 int i;
2557 for (i = 0; i < table->rows; ++i) {
2558 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2560 if (!is_vald_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
2561 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2565 static void
2566 verify_field_marshal_table (VerifyContext *ctx)
2568 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2569 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2570 int i;
2572 for (i = 0; i < table->rows; ++i) {
2573 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2575 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2576 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
2578 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2579 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
2581 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
2582 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
2584 if (!is_valid_blob_object (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE], 1))
2585 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d invalid NativeType blob 0x%x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2589 static void
2590 verify_field_marshal_table_full (VerifyContext *ctx)
2592 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2593 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2594 int i;
2596 for (i = 0; i < table->rows; ++i) {
2597 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2599 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
2600 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2604 static void
2605 verify_decl_security_table (VerifyContext *ctx)
2607 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2608 guint32 data [MONO_DECL_SECURITY_SIZE];
2609 int i;
2611 for (i = 0; i < table->rows; ++i) {
2612 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2614 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2615 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
2617 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2618 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
2620 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
2621 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
2625 static void
2626 verify_decl_security_table_full (VerifyContext *ctx)
2628 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2629 guint32 data [MONO_DECL_SECURITY_SIZE];
2630 int i;
2632 for (i = 0; i < table->rows; ++i) {
2633 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2635 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
2636 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
2640 static void
2641 verify_class_layout_table (VerifyContext *ctx)
2643 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
2644 guint32 data [MONO_CLASS_LAYOUT_SIZE];
2645 int i;
2647 for (i = 0; i < table->rows; ++i) {
2648 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
2650 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2651 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2653 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
2654 case 0:
2655 case 1:
2656 case 2:
2657 case 4:
2658 case 8:
2659 case 16:
2660 case 32:
2661 case 64:
2662 case 128:
2663 break;
2664 default:
2665 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
2670 static void
2671 verify_field_layout_table (VerifyContext *ctx)
2673 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
2674 guint32 data [MONO_FIELD_LAYOUT_SIZE];
2675 int i;
2677 for (i = 0; i < table->rows; ++i) {
2678 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
2680 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2681 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
2685 static void
2686 verify_standalonesig_table (VerifyContext *ctx)
2688 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
2689 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
2690 int i;
2692 for (i = 0; i < table->rows; ++i) {
2693 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
2695 if (data [MONO_STAND_ALONE_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_STAND_ALONE_SIGNATURE], 1))
2696 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d invalid signature 0x%x", i, data [MONO_STAND_ALONE_SIGNATURE]));
2700 static void
2701 verify_standalonesig_table_full (VerifyContext *ctx)
2703 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
2704 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
2705 int i;
2707 for (i = 0; i < table->rows; ++i) {
2708 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
2710 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
2711 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
2715 static void
2716 verify_eventmap_table (VerifyContext *ctx)
2718 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
2719 guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
2720 int i;
2722 for (i = 0; i < table->rows; ++i) {
2723 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
2725 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2726 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
2728 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
2729 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
2731 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
2735 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
2736 static void
2737 verify_event_table (VerifyContext *ctx)
2739 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
2740 guint32 data [MONO_EVENT_SIZE];
2741 int i;
2743 for (i = 0; i < table->rows; ++i) {
2744 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
2746 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
2747 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
2749 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
2750 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
2752 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
2753 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
2757 static void
2758 verify_event_table_full (VerifyContext *ctx)
2760 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
2761 MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
2762 guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
2763 gboolean found_add, found_remove;
2764 int i, idx;
2766 for (i = 0; i < table->rows; ++i) {
2767 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
2769 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
2770 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
2771 if (idx == -1)
2772 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
2774 //first we move to the first row for this event
2775 while (idx > 0) {
2776 if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
2777 break;
2778 --idx;
2780 //now move forward looking for AddOn and RemoveOn rows
2781 found_add = found_remove = FALSE;
2782 while (idx < sema_table->rows) {
2783 mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
2784 if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
2785 break;
2786 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
2787 found_add = TRUE;
2788 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
2789 found_remove = TRUE;
2790 if (found_add && found_remove)
2791 break;
2792 ++idx;
2795 if (!found_add)
2796 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2797 if (!found_remove)
2798 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2802 static void
2803 verify_propertymap_table (VerifyContext *ctx)
2805 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
2806 guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
2807 int i;
2809 for (i = 0; i < table->rows; ++i) {
2810 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
2812 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2813 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
2815 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
2816 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
2818 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
2822 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
2823 static void
2824 verify_property_table (VerifyContext *ctx)
2826 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
2827 guint32 data [MONO_PROPERTY_SIZE];
2828 int i;
2830 for (i = 0; i < table->rows; ++i) {
2831 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
2833 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
2834 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
2836 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
2837 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
2839 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
2840 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
2842 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
2843 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
2844 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
2849 static void
2850 verify_methodimpl_table (VerifyContext *ctx)
2852 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
2853 guint32 data [MONO_METHODIMPL_SIZE];
2854 int i;
2856 for (i = 0; i < table->rows; ++i) {
2857 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
2859 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2860 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2862 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2863 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2865 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2866 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2868 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2869 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2871 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2872 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2876 static void
2877 verify_moduleref_table (VerifyContext *ctx)
2879 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
2880 guint32 data [MONO_MODULEREF_SIZE];
2881 int i;
2883 for (i = 0; i < table->rows; ++i) {
2884 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
2886 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
2887 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2891 static void
2892 verify_typespec_table (VerifyContext *ctx)
2894 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
2895 guint32 data [MONO_TYPESPEC_SIZE];
2896 int i;
2898 for (i = 0; i < table->rows; ++i) {
2899 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
2901 if (data [MONO_TYPESPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_TYPESPEC_SIGNATURE], 1))
2902 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
2906 static void
2907 verify_typespec_table_full (VerifyContext *ctx)
2909 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
2910 guint32 data [MONO_TYPESPEC_SIZE];
2911 int i;
2913 for (i = 0; i < table->rows; ++i) {
2914 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
2915 ctx->token = (i + 1) | MONO_TOKEN_TYPE_SPEC;
2916 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
2917 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
2919 ctx->token = 0;
2922 #define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 6) | (1 << 8) | (1 << 9) | (1 << 10))
2923 static void
2924 verify_implmap_table (VerifyContext *ctx)
2926 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
2927 guint32 data [MONO_IMPLMAP_SIZE], cconv;
2928 int i;
2930 for (i = 0; i < table->rows; ++i) {
2931 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
2933 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
2934 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
2936 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
2937 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
2938 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
2940 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2941 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
2943 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
2944 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
2946 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2947 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
2949 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
2950 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
2952 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULEREF].rows + 1)
2953 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
2957 static void
2958 verify_fieldrva_table (VerifyContext *ctx)
2960 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
2961 guint32 data [MONO_FIELD_RVA_SIZE];
2962 int i;
2964 for (i = 0; i < table->rows; ++i) {
2965 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
2967 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
2968 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
2970 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2971 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
2975 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 4) | (1 << 8) | (1 << 14) | (1 << 15))
2976 static void
2977 verify_assembly_table (VerifyContext *ctx)
2979 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
2980 guint32 data [MONO_ASSEMBLY_SIZE], hash;
2981 int i;
2983 if (table->rows > 1)
2984 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
2986 for (i = 0; i < table->rows; ++i) {
2987 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
2989 hash = data [MONO_ASSEMBLY_HASH_ALG];
2990 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
2991 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
2993 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
2994 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2996 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY], 1))
2997 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2999 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
3000 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
3002 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
3003 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
3007 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~(1)
3008 static void
3009 verify_assemblyref_table (VerifyContext *ctx)
3011 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
3012 guint32 data [MONO_ASSEMBLYREF_SIZE];
3013 int i;
3015 for (i = 0; i < table->rows; ++i) {
3016 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
3018 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
3019 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
3021 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY], 1))
3022 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
3024 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
3025 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
3027 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
3028 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
3030 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE], 1))
3031 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
3035 #define INVALID_FILE_FLAGS_BITS ~(1)
3036 static void
3037 verify_file_table (VerifyContext *ctx)
3039 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
3040 guint32 data [MONO_FILE_SIZE];
3041 int i;
3043 for (i = 0; i < table->rows; ++i) {
3044 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
3046 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
3047 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
3049 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
3050 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
3052 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE], 1))
3053 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
3057 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
3058 static void
3059 verify_exportedtype_table (VerifyContext *ctx)
3061 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
3062 guint32 data [MONO_EXP_TYPE_SIZE];
3063 int i;
3065 for (i = 0; i < table->rows; ++i) {
3066 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
3068 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
3069 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
3071 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
3072 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
3074 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
3075 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
3077 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3078 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
3080 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3081 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
3083 /*nested type can't have a namespace*/
3084 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
3085 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
3089 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
3090 static void
3091 verify_manifest_resource_table (VerifyContext *ctx)
3093 MonoCLIImageInfo *iinfo = ctx->image->image_info;
3094 MonoCLIHeader *ch = &iinfo->cli_cli_header;
3095 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
3096 guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
3097 int i;
3099 resources_size = ch->ch_resources.size;
3101 for (i = 0; i < table->rows; ++i) {
3102 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
3104 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
3105 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
3107 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
3108 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
3110 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
3111 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
3113 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
3114 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
3116 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3117 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3119 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
3120 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])));
3122 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
3123 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
3125 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
3126 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
3130 static void
3131 verify_nested_class_table (VerifyContext *ctx)
3133 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3134 guint32 data [MONO_NESTED_CLASS_SIZE];
3135 int i;
3137 for (i = 0; i < table->rows; ++i) {
3138 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
3140 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3141 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
3142 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3143 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3144 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
3145 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3149 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
3150 static void
3151 verify_generic_param_table (VerifyContext *ctx)
3153 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
3154 guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
3155 int i, param_number = 0;
3157 for (i = 0; i < table->rows; ++i) {
3158 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
3160 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
3161 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
3163 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
3164 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
3166 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
3167 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
3169 token = data [MONO_GENERICPARAM_OWNER];
3171 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
3172 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
3174 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
3175 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
3177 if (token != last_token) {
3178 param_number = 0;
3179 last_token = token;
3182 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
3183 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));
3185 ++param_number;
3189 static void
3190 verify_method_spec_table (VerifyContext *ctx)
3192 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3193 guint32 data [MONO_METHODSPEC_SIZE];
3194 int i;
3196 for (i = 0; i < table->rows; ++i) {
3197 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3199 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3200 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
3202 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3203 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
3205 if (data [MONO_METHODSPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHODSPEC_SIGNATURE], 1))
3206 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid signature token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3210 static void
3211 verify_method_spec_table_full (VerifyContext *ctx)
3213 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3214 guint32 data [MONO_METHODSPEC_SIZE];
3215 int i;
3217 for (i = 0; i < table->rows; ++i) {
3218 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3220 if (!is_valid_methodspec_blob (ctx, data [MONO_METHODSPEC_SIGNATURE]))
3221 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3225 static void
3226 verify_generic_param_constraint_table (VerifyContext *ctx)
3228 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
3229 guint32 data [MONO_GENPARCONSTRAINT_SIZE];
3230 int i;
3232 for (i = 0; i < table->rows; ++i) {
3233 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
3235 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
3236 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_TABLE_GENERICPARAM]));
3238 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3239 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
3241 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3242 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
3247 typedef struct {
3248 const char *name;
3249 const char *name_space;
3250 guint32 resolution_scope;
3251 } TypeDefUniqueId;
3253 static guint
3254 typedef_hash (gconstpointer _key)
3256 const TypeDefUniqueId *key = _key;
3257 return g_str_hash (key->name) ^ g_str_hash (key->name_space) ^ key->resolution_scope; /*XXX better salt the int key*/
3260 static gboolean
3261 typedef_equals (gconstpointer _a, gconstpointer _b)
3263 const TypeDefUniqueId *a = _a;
3264 const TypeDefUniqueId *b = _b;
3265 return !strcmp (a->name, b->name) && !strcmp (a->name_space, b->name_space) && a->resolution_scope == b->resolution_scope;
3268 static void
3269 verify_typedef_table_global_constraints (VerifyContext *ctx)
3271 int i;
3272 guint32 data [MONO_TYPEDEF_SIZE];
3273 guint32 nested_data [MONO_NESTED_CLASS_SIZE];
3274 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
3275 MonoTableInfo *nested_table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3276 GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3278 for (i = 0; i < table->rows; ++i) {
3279 guint visibility;
3280 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3281 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
3283 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAME]);
3284 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAMESPACE]);
3285 type->resolution_scope = 0;
3287 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
3288 if (visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) {
3289 int res = search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1);
3290 g_assert (res >= 0);
3292 mono_metadata_decode_row (nested_table, res, nested_data, MONO_NESTED_CLASS_SIZE);
3293 type->resolution_scope = nested_data [MONO_NESTED_CLASS_ENCLOSING];
3296 if (g_hash_table_lookup (unique_types, type)) {
3297 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));
3298 g_hash_table_destroy (unique_types);
3299 g_free (type);
3300 return;
3302 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3305 g_hash_table_destroy (unique_types);
3308 static void
3309 verify_typeref_table_global_constraints (VerifyContext *ctx)
3311 int i;
3312 guint32 data [MONO_TYPEREF_SIZE];
3313 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
3314 GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3316 for (i = 0; i < table->rows; ++i) {
3317 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3318 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
3320 type->resolution_scope = data [MONO_TYPEREF_SCOPE];
3321 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAME]);
3322 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAMESPACE]);
3324 if (g_hash_table_lookup (unique_types, type)) {
3325 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));
3326 g_hash_table_destroy (unique_types);
3327 g_free (type);
3328 return;
3330 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3333 g_hash_table_destroy (unique_types);
3336 static void
3337 verify_tables_data_global_constraints (VerifyContext *ctx)
3339 verify_typeref_table_global_constraints (ctx);
3340 CHECK_ERROR ();
3341 verify_typedef_table_global_constraints (ctx);
3344 static void
3345 verify_tables_data (VerifyContext *ctx)
3347 OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
3348 guint32 size = 0, tables_offset;
3349 int i;
3351 for (i = 0; i < 0x2D; ++i) {
3352 MonoTableInfo *table = &ctx->image->tables [i];
3353 guint32 tmp_size;
3354 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
3355 if (tmp_size < size) {
3356 size = 0;
3357 break;
3359 size = tmp_size;
3362 if (size == 0)
3363 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
3365 tables_offset = ctx->image->tables_base - ctx->data;
3366 if (!bounds_check_offset (&tables_area, tables_offset, size))
3367 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)));
3369 verify_module_table (ctx);
3370 CHECK_ERROR ();
3371 verify_typeref_table (ctx);
3372 CHECK_ERROR ();
3373 verify_typedef_table (ctx);
3374 CHECK_ERROR ();
3375 verify_field_table (ctx);
3376 CHECK_ERROR ();
3377 verify_method_table (ctx);
3378 CHECK_ERROR ();
3379 verify_param_table (ctx);
3380 CHECK_ERROR ();
3381 verify_interfaceimpl_table (ctx);
3382 CHECK_ERROR ();
3383 verify_memberref_table (ctx);
3384 CHECK_ERROR ();
3385 verify_constant_table (ctx);
3386 CHECK_ERROR ();
3387 verify_cattr_table (ctx);
3388 CHECK_ERROR ();
3389 verify_field_marshal_table (ctx);
3390 CHECK_ERROR ();
3391 verify_decl_security_table (ctx);
3392 CHECK_ERROR ();
3393 verify_class_layout_table (ctx);
3394 CHECK_ERROR ();
3395 verify_field_layout_table (ctx);
3396 CHECK_ERROR ();
3397 verify_standalonesig_table (ctx);
3398 CHECK_ERROR ();
3399 verify_eventmap_table (ctx);
3400 CHECK_ERROR ();
3401 verify_event_table (ctx);
3402 CHECK_ERROR ();
3403 verify_propertymap_table (ctx);
3404 CHECK_ERROR ();
3405 verify_property_table (ctx);
3406 CHECK_ERROR ();
3407 verify_methodimpl_table (ctx);
3408 CHECK_ERROR ();
3409 verify_moduleref_table (ctx);
3410 CHECK_ERROR ();
3411 verify_typespec_table (ctx);
3412 CHECK_ERROR ();
3413 verify_implmap_table (ctx);
3414 CHECK_ERROR ();
3415 verify_fieldrva_table (ctx);
3416 CHECK_ERROR ();
3417 verify_assembly_table (ctx);
3418 CHECK_ERROR ();
3419 verify_assemblyref_table (ctx);
3420 CHECK_ERROR ();
3421 verify_file_table (ctx);
3422 CHECK_ERROR ();
3423 verify_exportedtype_table (ctx);
3424 CHECK_ERROR ();
3425 verify_manifest_resource_table (ctx);
3426 CHECK_ERROR ();
3427 verify_nested_class_table (ctx);
3428 CHECK_ERROR ();
3429 verify_generic_param_table (ctx);
3430 CHECK_ERROR ();
3431 verify_method_spec_table (ctx);
3432 CHECK_ERROR ();
3433 verify_generic_param_constraint_table (ctx);
3434 CHECK_ERROR ();
3435 verify_tables_data_global_constraints (ctx);
3438 static void
3439 init_verify_context (VerifyContext *ctx, MonoImage *image, GSList **error_list)
3441 memset (ctx, 0, sizeof (VerifyContext));
3442 ctx->image = image;
3443 ctx->report_error = error_list != NULL;
3444 ctx->report_warning = FALSE; //export this setting in the API
3445 ctx->valid = 1;
3446 ctx->size = image->raw_data_len;
3447 ctx->data = image->raw_data;
3450 static gboolean
3451 cleanup_context (VerifyContext *ctx, GSList **error_list)
3453 g_free (ctx->sections);
3454 if (error_list)
3455 *error_list = ctx->errors;
3456 else
3457 mono_free_verify_list (ctx->errors);
3458 return ctx->valid;
3461 gboolean
3462 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3464 VerifyContext ctx;
3466 if (!mono_verifier_is_enabled_for_image (image))
3467 return TRUE;
3469 init_verify_context (&ctx, image, error_list);
3470 ctx.stage = STAGE_PE;
3472 verify_msdos_header (&ctx);
3473 CHECK_STATE();
3474 verify_pe_header (&ctx);
3475 CHECK_STATE();
3476 verify_pe_optional_header (&ctx);
3477 CHECK_STATE();
3478 load_section_table (&ctx);
3479 CHECK_STATE();
3480 load_data_directories (&ctx);
3481 CHECK_STATE();
3482 verify_import_table (&ctx);
3483 CHECK_STATE();
3484 /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
3485 verify_resources_table (&ctx);
3487 cleanup:
3488 return cleanup_context (&ctx, error_list);
3491 gboolean
3492 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3494 VerifyContext ctx;
3496 if (!mono_verifier_is_enabled_for_image (image))
3497 return TRUE;
3499 init_verify_context (&ctx, image, error_list);
3500 ctx.stage = STAGE_CLI;
3502 verify_cli_header (&ctx);
3503 CHECK_STATE();
3504 verify_metadata_header (&ctx);
3505 CHECK_STATE();
3506 verify_tables_schema (&ctx);
3508 cleanup:
3509 return cleanup_context (&ctx, error_list);
3514 * Verifies basic table constraints such as global table invariants (sorting, field monotonicity, etc).
3515 * Other verification checks are meant to be done lazily by the runtime. Those include:
3516 * blob items (signatures, method headers, custom attributes, etc)
3517 * type semantics related
3518 * vtable related
3519 * stuff that should not block other pieces from running such as bad types/methods/fields/etc.
3521 * The whole idea is that if this succeed the runtime is free to play around safely but any complex
3522 * operation still need more checking.
3524 gboolean
3525 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3527 VerifyContext ctx;
3529 if (!mono_verifier_is_enabled_for_image (image))
3530 return TRUE;
3532 init_verify_context (&ctx, image, error_list);
3533 ctx.stage = STAGE_TABLES;
3535 verify_tables_data (&ctx);
3537 return cleanup_context (&ctx, error_list);
3542 * Verifies all other constraints.
3544 gboolean
3545 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3547 VerifyContext ctx;
3549 if (!mono_verifier_is_enabled_for_image (image))
3550 return TRUE;
3552 init_verify_context (&ctx, image, error_list);
3553 ctx.stage = STAGE_TABLES;
3555 verify_typedef_table_full (&ctx);
3556 CHECK_STATE ();
3557 verify_field_table_full (&ctx);
3558 CHECK_STATE ();
3559 verify_method_table_full (&ctx);
3560 CHECK_STATE ();
3561 verify_memberref_table_full (&ctx);
3562 CHECK_STATE ();
3563 verify_cattr_table_full (&ctx);
3564 CHECK_STATE ();
3565 verify_field_marshal_table_full (&ctx);
3566 CHECK_STATE ();
3567 verify_decl_security_table_full (&ctx);
3568 CHECK_STATE ();
3569 verify_standalonesig_table_full (&ctx);
3570 CHECK_STATE ();
3571 verify_event_table_full (&ctx);
3572 CHECK_STATE ();
3573 verify_typespec_table_full (&ctx);
3574 CHECK_STATE ();
3575 verify_method_spec_table_full (&ctx);
3577 cleanup:
3578 return cleanup_context (&ctx, error_list);
3581 gboolean
3582 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
3584 VerifyContext ctx;
3586 if (!mono_verifier_is_enabled_for_image (image))
3587 return TRUE;
3589 init_verify_context (&ctx, image, error_list);
3590 ctx.stage = STAGE_TABLES;
3592 is_valid_field_signature (&ctx, offset);
3593 return cleanup_context (&ctx, error_list);
3596 gboolean
3597 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
3599 VerifyContext ctx;
3601 if (!mono_verifier_is_enabled_for_image (image))
3602 return TRUE;
3604 init_verify_context (&ctx, image, error_list);
3605 ctx.stage = STAGE_TABLES;
3607 is_valid_method_header (&ctx, offset);
3608 return cleanup_context (&ctx, error_list);
3611 gboolean
3612 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
3614 VerifyContext ctx;
3616 if (!mono_verifier_is_enabled_for_image (image))
3617 return TRUE;
3619 init_verify_context (&ctx, image, error_list);
3620 ctx.stage = STAGE_TABLES;
3622 is_valid_method_signature (&ctx, offset);
3623 return cleanup_context (&ctx, error_list);
3626 gboolean
3627 mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
3629 VerifyContext ctx;
3631 if (!mono_verifier_is_enabled_for_image (image))
3632 return TRUE;
3634 init_verify_context (&ctx, image, error_list);
3635 ctx.stage = STAGE_TABLES;
3637 is_valid_method_or_field_signature (&ctx, offset);
3638 return cleanup_context (&ctx, error_list);
3641 gboolean
3642 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
3644 VerifyContext ctx;
3646 if (!mono_verifier_is_enabled_for_image (image))
3647 return TRUE;
3649 init_verify_context (&ctx, image, error_list);
3650 ctx.stage = STAGE_TABLES;
3652 is_valid_standalonesig_blob (&ctx, offset);
3653 return cleanup_context (&ctx, error_list);
3656 gboolean
3657 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
3659 VerifyContext ctx;
3661 if (!mono_verifier_is_enabled_for_image (image))
3662 return TRUE;
3664 init_verify_context (&ctx, image, error_list);
3665 ctx.stage = STAGE_TABLES;
3666 ctx.token = token;
3668 is_valid_typespec_blob (&ctx, offset);
3669 return cleanup_context (&ctx, error_list);
3672 gboolean
3673 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3675 VerifyContext ctx;
3677 if (!mono_verifier_is_enabled_for_image (image))
3678 return TRUE;
3680 init_verify_context (&ctx, image, error_list);
3681 ctx.stage = STAGE_TABLES;
3683 is_valid_methodspec_blob (&ctx, offset);
3684 return cleanup_context (&ctx, error_list);
3687 static void
3688 verify_user_string (VerifyContext *ctx, guint32 offset)
3690 OffsetAndSize heap_us = get_metadata_stream (ctx, &ctx->image->heap_us);
3691 guint32 entry_size, bytes;
3693 if (heap_us.size < offset)
3694 ADD_ERROR (ctx, g_strdup ("User string offset beyond heap_us size"));
3696 if (!decode_value (ctx->data + offset + heap_us.offset, heap_us.size - heap_us.offset, &entry_size, &bytes))
3697 ADD_ERROR (ctx, g_strdup ("Could not decode user string blob size"));
3699 if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
3700 ADD_ERROR (ctx, g_strdup ("User string size overflow"));
3702 entry_size += bytes;
3704 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, heap_us.size))
3705 ADD_ERROR (ctx, g_strdup ("User string oveflow heap_us"));
3708 gboolean
3709 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
3711 VerifyContext ctx;
3713 if (!mono_verifier_is_enabled_for_image (image))
3714 return TRUE;
3716 init_verify_context (&ctx, image, error_list);
3717 ctx.stage = STAGE_TABLES;
3719 verify_user_string (&ctx, offset);
3721 return cleanup_context (&ctx, error_list);
3724 gboolean
3725 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
3727 MonoMethodSignature *original_sig;
3728 if (!mono_verifier_is_enabled_for_image (image))
3729 return TRUE;
3731 original_sig = mono_method_signature (method);
3732 if (original_sig->call_convention == MONO_CALL_VARARG) {
3733 if (original_sig->hasthis != signature->hasthis)
3734 return FALSE;
3735 if (original_sig->call_convention != signature->call_convention)
3736 return FALSE;
3737 if (original_sig->explicit_this != signature->explicit_this)
3738 return FALSE;
3739 if (original_sig->call_convention != signature->call_convention)
3740 return FALSE;
3741 if (original_sig->pinvoke != signature->pinvoke)
3742 return FALSE;
3743 if (original_sig->sentinelpos != signature->sentinelpos)
3744 return FALSE;
3745 } else if (!mono_metadata_signature_equal (signature, original_sig)) {
3746 return FALSE;
3749 return TRUE;
3752 #else
3753 gboolean
3754 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3756 return TRUE;
3759 gboolean
3760 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3762 return TRUE;
3765 gboolean
3766 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3768 return TRUE;
3771 gboolean
3772 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3774 return TRUE;
3777 gboolean
3778 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
3780 return TRUE;
3783 gboolean
3784 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
3786 return TRUE;
3789 gboolean
3790 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
3792 return TRUE;
3795 gboolean
3796 mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
3798 return TRUE;
3801 gboolean
3802 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
3804 return TRUE;
3807 gboolean
3808 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
3810 return TRUE;
3813 gboolean
3814 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
3816 return TRUE;
3819 gboolean
3820 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
3822 return TRUE;
3825 gboolean
3826 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
3828 return TRUE;
3832 #endif /* DISABLE_VERIFIER */