2009-06-22 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / metadata / metadata-verify.c
1 /*
2  * metadata-verify.c: Metadata verfication support
3  *
4  * Author:
5  *      Mono Project (http://www.mono-project.com)
6  *
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>
29
30 #ifndef DISABLE_VERIFIER
31 /*
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
46 */
47
48 #ifdef MONO_VERIFIER_DEBUG
49 #define VERIFIER_DEBUG(code) do { code; } while (0)
50 #else
51 #define VERIFIER_DEBUG(code)
52 #endif
53
54 #define INVALID_OFFSET ((guint32)-1)
55 #define INVALID_ADDRESS 0xffffffff
56
57 enum {
58         STAGE_PE,
59         STAGE_CLI,
60         STAGE_TABLES
61 };
62
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,
70 };
71
72 enum {
73         STRINGS_STREAM,
74         USER_STRINGS_STREAM,
75         BLOB_STREAM,
76         GUID_STREAM,
77         TILDE_STREAM
78 };
79
80
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,
90
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,
97
98 #define HAS_CATTR_DESC (HAS_CONSTANT_DESC + 5)
99         5, /*bits*/
100         19, /*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
121 #define HAS_FIELD_MARSHAL_DESC (HAS_CATTR_DESC + 21)
122         1, /*bits*/
123         2, /*tables*/
124         MONO_TABLE_FIELD,
125         MONO_TABLE_PARAM,
126
127 #define HAS_DECL_SECURITY_DESC (HAS_FIELD_MARSHAL_DESC + 4)
128         2, /*bits*/
129         3, /*tables*/
130         MONO_TABLE_TYPEDEF,
131         MONO_TABLE_METHOD,
132         MONO_TABLE_ASSEMBLY,
133
134 #define MEMBERREF_PARENT_DESC (HAS_DECL_SECURITY_DESC + 5)
135         3, /*bits*/
136         5, /*tables*/
137         MONO_TABLE_TYPEDEF,
138         MONO_TABLE_TYPEREF,
139         MONO_TABLE_MODULE,
140         MONO_TABLE_METHOD,
141         MONO_TABLE_TYPESPEC,
142
143 #define HAS_SEMANTICS_DESC (MEMBERREF_PARENT_DESC + 7)
144         1, /*bits*/
145         2, /*tables*/
146         MONO_TABLE_EVENT,
147         MONO_TABLE_PROPERTY,
148
149 #define METHODDEF_OR_REF_DESC (HAS_SEMANTICS_DESC + 4)
150         1, /*bits*/
151         2, /*tables*/
152         MONO_TABLE_METHOD,
153         MONO_TABLE_MEMBERREF,
154
155 #define MEMBER_FORWARDED_DESC (METHODDEF_OR_REF_DESC + 4)
156         1, /*bits*/
157         2, /*tables*/
158         MONO_TABLE_FIELD,
159         MONO_TABLE_METHOD,
160
161 #define IMPLEMENTATION_DESC (MEMBER_FORWARDED_DESC + 4)
162         2, /*bits*/
163         3, /*tables*/
164         MONO_TABLE_FILE,
165         MONO_TABLE_ASSEMBLYREF,
166         MONO_TABLE_EXPORTEDTYPE,
167
168 #define CATTR_TYPE_DESC (IMPLEMENTATION_DESC + 5)
169         3, /*bits*/
170         5, /*tables*/
171         INVALID_TABLE,
172         INVALID_TABLE,
173         MONO_TABLE_METHOD,
174         MONO_TABLE_MEMBERREF,
175         INVALID_TABLE,
176
177 #define RES_SCOPE_DESC (CATTR_TYPE_DESC + 7)
178         2, /*bits*/
179         4, /*tables*/
180         MONO_TABLE_MODULE,
181         MONO_TABLE_MODULEREF,
182         MONO_TABLE_ASSEMBLYREF,
183         MONO_TABLE_TYPEREF,
184
185 #define TYPE_OR_METHODDEF_DESC (RES_SCOPE_DESC + 6)
186         1, /*bits*/
187         2, /*tables*/
188         MONO_TABLE_TYPEDEF,
189         MONO_TABLE_METHOD
190 };
191
192 typedef struct {
193         guint32 rva;
194         guint32 size;
195         guint32 translated_offset;
196 } DataDirectory;
197
198 typedef struct {
199         guint32 offset;
200         guint32 size;
201 } OffsetAndSize;
202
203 typedef struct {
204         guint32 baseRVA;
205         guint32 baseOffset;
206         guint32 size;
207         guint32 rellocationsRVA;
208         guint16 numberOfRelocations;
209 } SectionHeader;
210
211 typedef struct {
212         guint32 row_count;
213         guint32 row_size;
214         guint32 offset;
215 } TableInfo;
216
217 typedef struct {
218         const char *data;
219         guint32 size;
220         GSList *errors;
221         int valid;
222         MonoImage *image;
223         gboolean report_error;
224         int stage;
225
226         DataDirectory data_directories [16];
227         guint32 section_count;
228         SectionHeader *sections;
229
230         OffsetAndSize metadata_streams [5]; //offset from begin of the image
231 } VerifyContext;
232
233 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception)    \
234         do {    \
235                 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1);      \
236                 vinfo->info.status = __status;  \
237                 vinfo->info.message = ( __msg); \
238                 vinfo->exception_type = (__exception);  \
239                 (__ctx)->errors = g_slist_prepend ((__ctx)->errors, vinfo);     \
240         } while (0)
241
242
243 #define ADD_ERROR(__ctx, __msg) \
244         do {    \
245                 if ((__ctx)->report_error) \
246                         ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
247                 (__ctx)->valid = 0; \
248                 return; \
249         } while (0)
250
251 #define FAIL(__ctx, __msg)      \
252         do {    \
253                 if ((__ctx)->report_error) \
254                         ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
255                 (__ctx)->valid = 0; \
256                 return FALSE; \
257         } while (0)
258
259 #define CHECK_STATE() do { if (!ctx.valid) goto cleanup; } while (0)
260
261 #define CHECK_ERROR() do { if (!ctx->valid) return; } while (0)
262
263 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
264 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
265
266 #if SIZEOF_VOID_P == 4
267 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
268 #else
269 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
270 #endif
271
272 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
273
274 static const char *
275 dword_align (const char *ptr)
276 {
277 #if SIZEOF_VOID_P == 8
278         return (const char *) (((guint64) (ptr + 3)) & ~3);
279 #else
280         return (const char *) (((guint32) (ptr + 3)) & ~3);
281 #endif
282 }
283
284 static guint32
285 pe_signature_offset (VerifyContext *ctx)
286 {
287         return read32 (ctx->data + 0x3c);
288 }
289
290 static guint32
291 pe_header_offset (VerifyContext *ctx)
292 {
293         return read32 (ctx->data + 0x3c) + 4;
294 }
295
296 static gboolean
297 bounds_check_virtual_address (VerifyContext *ctx, guint32 rva, guint32 size)
298 {
299         int i;
300
301         if (rva + size < rva) //overflow
302                 return FALSE;
303
304         if (ctx->stage > STAGE_PE) {
305                 MonoCLIImageInfo *iinfo = ctx->image->image_info;
306                 const int top = iinfo->cli_section_count;
307                 MonoSectionTable *tables = iinfo->cli_section_tables;
308                 int i;
309                 
310                 for (i = 0; i < top; i++) {
311                         guint32 base = tables->st_virtual_address;
312                         guint32 end = base + tables->st_raw_data_size;
313
314                         if (rva >= base && rva + size <= end)
315                                 return TRUE;
316
317                         /*if ((addr >= tables->st_virtual_address) &&
318                             (addr < tables->st_virtual_address + tables->st_raw_data_size)){
319
320                                 return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
321                         }*/
322                         tables++;
323                 }
324                 return FALSE;
325         }
326
327         if (!ctx->sections)
328                 return FALSE;
329
330         for (i = 0; i < ctx->section_count; ++i) {
331                 guint32 base = ctx->sections [i].baseRVA;
332                 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
333                 if (rva >= base && rva + size <= end)
334                         return TRUE;
335         }
336         return FALSE;
337 }
338
339 static gboolean
340 bounds_check_datadir (DataDirectory *dir, guint32 offset, guint32 size)
341 {
342         if (dir->translated_offset > offset)
343                 return FALSE;
344         if (dir->size < size)
345                 return FALSE;
346         return offset + size <= dir->translated_offset + dir->size;
347 }
348
349 static gboolean
350 bounds_check_offset (OffsetAndSize *off, guint32 offset, guint32 size)
351 {
352         if (off->offset > offset)
353                 return FALSE;
354         
355         if (off->size < size)
356                 return FALSE;
357
358         return offset + size <= off->offset + off->size;
359 }
360
361 static guint32
362 translate_rva (VerifyContext *ctx, guint32 rva)
363 {
364         int i;
365
366         if (ctx->stage > STAGE_PE)
367                 return mono_cli_rva_image_map (ctx->image, rva);
368                 
369         if (!ctx->sections)
370                 return FALSE;
371
372         for (i = 0; i < ctx->section_count; ++i) {
373                 guint32 base = ctx->sections [i].baseRVA;
374                 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
375                 if (rva >= base && rva <= end) {
376                         guint32 res = (rva - base) + ctx->sections [i].baseOffset;
377                         /* double check */
378                         return res >= ctx->size ? INVALID_OFFSET : res;
379                 }
380         }
381
382         return INVALID_OFFSET;
383 }
384
385 static void
386 verify_msdos_header (VerifyContext *ctx)
387 {
388         guint32 lfanew;
389         if (ctx->size < 128)
390                 ADD_ERROR (ctx, g_strdup ("Not enough space for the MS-DOS header"));
391         if (ctx->data [0] != 0x4d || ctx->data [1] != 0x5a)
392                 ADD_ERROR (ctx,  g_strdup ("Invalid MS-DOS watermark"));
393         lfanew = pe_signature_offset (ctx);
394         if (lfanew > ctx->size - 4)
395                 ADD_ERROR (ctx, g_strdup ("MS-DOS lfanew offset points to outside of the file"));
396 }
397
398 static void
399 verify_pe_header (VerifyContext *ctx)
400 {
401         guint32 offset = pe_signature_offset (ctx);
402         const char *pe_header = ctx->data + offset;
403         if (pe_header [0] != 'P' || pe_header [1] != 'E' ||pe_header [2] != 0 ||pe_header [3] != 0)
404                 ADD_ERROR (ctx,  g_strdup ("Invalid PE header watermark"));
405         pe_header += 4;
406         offset += 4;
407
408         if (offset > ctx->size - 20)
409                 ADD_ERROR (ctx, g_strdup ("File with truncated pe header"));
410         if (read16 (pe_header) != 0x14c)
411                 ADD_ERROR (ctx, g_strdup ("Invalid PE header Machine value"));
412 }
413
414 static void
415 verify_pe_optional_header (VerifyContext *ctx)
416 {
417         guint32 offset = pe_header_offset (ctx);
418         guint32 header_size, file_alignment;
419         const char *pe_header = ctx->data + offset;
420         const char *pe_optional_header = pe_header + 20;
421
422         header_size = read16 (pe_header + 16);
423         offset += 20;
424
425         if (header_size < 2) /*must be at least 2 or we won't be able to read magic*/
426                 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
427
428         if (offset > ctx->size - header_size || header_size > ctx->size)
429                 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
430
431         if (read16 (pe_optional_header) == 0x10b) {
432                 if (header_size != 224)
433                         ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header size %d", header_size));
434
435                 /* LAMESPEC MS plays around this value and ignore it during validation
436                 if (read32 (pe_optional_header + 28) != 0x400000)
437                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Image base %x", read32 (pe_optional_header + 28)));*/
438                 if (read32 (pe_optional_header + 32) != 0x2000)
439                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Section Aligmnent %x", read32 (pe_optional_header + 32)));
440                 file_alignment = read32 (pe_optional_header + 36);
441                 if (file_alignment != 0x200 && file_alignment != 0x1000)
442                         ADD_ERROR (ctx, g_strdup_printf ("Invalid file Aligmnent %x", file_alignment));
443                 /* All the junk in the middle is irrelevant, specially for mono. */
444                 if (read32 (pe_optional_header + 92) > 0x10)
445                         ADD_ERROR (ctx, g_strdup_printf ("Too many data directories %x", read32 (pe_optional_header + 92)));
446         } else {
447                 if (read16 (pe_optional_header) == 0x20B)
448                         ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle PE32+"));
449                 else
450                         ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header magic %d", read16 (pe_optional_header)));
451         }
452 }
453
454 static void
455 load_section_table (VerifyContext *ctx)
456 {
457         int i;
458         SectionHeader *sections;
459         guint32 offset =  pe_header_offset (ctx);
460         const char *ptr = ctx->data + offset;
461         guint16 num_sections = ctx->section_count = read16 (ptr + 2);
462
463         offset += 244;/*FIXME, this constant is different under PE32+*/
464         ptr += 244;
465
466         if (num_sections * 40 > ctx->size - offset)
467                 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
468
469         sections = ctx->sections = g_new0 (SectionHeader, num_sections);
470         for (i = 0; i < num_sections; ++i) {
471                 sections [i].size = read32 (ptr + 8);
472                 sections [i].baseRVA = read32 (ptr + 12);
473                 sections [i].baseOffset = read32 (ptr + 20);
474                 sections [i].rellocationsRVA = read32 (ptr + 24);
475                 sections [i].numberOfRelocations = read16 (ptr + 32);
476                 ptr += 40;
477         }
478
479         ptr = ctx->data + offset; /*reset it to the beggining*/
480         for (i = 0; i < num_sections; ++i) {
481                 guint32 raw_size, flags;
482                 if (sections [i].baseOffset == 0)
483                         ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with intialized data only"));
484                 if (sections [i].baseOffset >= ctx->size)
485                         ADD_ERROR (ctx, g_strdup_printf ("Invalid PointerToRawData %x points beyond EOF", sections [i].baseOffset));
486                 if (sections [i].size > ctx->size - sections [i].baseOffset)
487                         ADD_ERROR (ctx, g_strdup ("Invalid VirtualSize points beyond EOF"));
488
489                 raw_size = read32 (ptr + 16);
490                 if (raw_size < sections [i].size)
491                         ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with SizeOfRawData < VirtualSize"));
492
493                 if (raw_size > ctx->size - sections [i].baseOffset)
494                         ADD_ERROR (ctx, g_strdup_printf ("Invalid SizeOfRawData %x points beyond EOF", raw_size));
495
496                 if (sections [i].rellocationsRVA || sections [i].numberOfRelocations)
497                         ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't handle section relocation"));
498
499                 flags = read32 (ptr + 36);
500                 /*TODO 0xFE0000E0 is all flags from cil-coff.h OR'd. Make it a less magical number*/
501                 if (flags == 0 || (flags & ~0xFE0000E0) != 0)
502                         ADD_ERROR (ctx, g_strdup_printf ("Invalid section flags %x", flags));
503
504                 ptr += 40;
505         }
506 }
507
508 static gboolean
509 is_valid_data_directory (int i)
510 {
511         /*LAMESPEC 4 == certificate 6 == debug, MS uses both*/
512         return i == 1 || i == 2 || i == 5 || i == 12 || i == 14 || i == 4 || i == 6; 
513 }
514
515 static void
516 load_data_directories (VerifyContext *ctx)
517 {
518         guint32 offset =  pe_header_offset (ctx) + 116; /*FIXME, this constant is different under PE32+*/
519         const char *ptr = ctx->data + offset;
520         int i;
521
522         for (i = 0; i < 16; ++i) {
523                 guint32 rva = read32 (ptr);
524                 guint32 size = read32 (ptr + 4);
525
526                 /*LAMESPEC the authenticode data directory format is different. We don't support CAS, so lets ignore for now.*/
527                 if (i == CERTIFICATE_TABLE_IDX) {
528                         ptr += 8;
529                         continue;
530                 }
531                 if ((rva != 0 || size != 0) && !is_valid_data_directory (i))
532                         ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d", i));
533
534                 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
535                         ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d rva/size pair %x/%x", i, rva, size));
536
537                 ctx->data_directories [i].rva = rva;
538                 ctx->data_directories [i].size = size;
539                 ctx->data_directories [i].translated_offset = translate_rva (ctx, rva);
540
541                 ptr += 8;
542         }
543 }
544
545 #define SIZE_OF_MSCOREE (sizeof ("mscoree.dll"))
546
547 #define SIZE_OF_CORMAIN (sizeof ("_CorExeMain"))
548
549 static void
550 verify_hint_name_table (VerifyContext *ctx, guint32 import_rva, const char *table_name)
551 {
552         const char *ptr;
553         guint32 hint_table_rva;
554
555         import_rva = translate_rva (ctx, import_rva);
556         g_assert (import_rva != INVALID_OFFSET);
557
558         hint_table_rva = read32 (ctx->data + import_rva);
559         if (!bounds_check_virtual_address (ctx, hint_table_rva, SIZE_OF_CORMAIN + 2))
560                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint/Name rva %d for %s", hint_table_rva, table_name));
561
562         hint_table_rva = translate_rva (ctx, hint_table_rva);
563         g_assert (hint_table_rva != INVALID_OFFSET);
564         ptr = ctx->data + hint_table_rva + 2;
565
566         if (memcmp ("_CorExeMain", ptr, SIZE_OF_CORMAIN) && memcmp ("_CorDllMain", ptr, SIZE_OF_CORMAIN)) {
567                 char name[SIZE_OF_CORMAIN];
568                 memcpy (name, ptr, SIZE_OF_CORMAIN);
569                 name [SIZE_OF_CORMAIN - 1] = 0;
570                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint / Name: '%s'", name));
571         }
572 }
573
574 static void
575 verify_import_table (VerifyContext *ctx)
576 {
577         DataDirectory it = ctx->data_directories [IMPORT_TABLE_IDX];
578         guint32 offset = it.translated_offset;
579         const char *ptr = ctx->data + offset;
580         guint32 name_rva, ilt_rva, iat_rva;
581
582         g_assert (offset != INVALID_OFFSET);
583
584         if (it.size < 40)
585                 ADD_ERROR (ctx, g_strdup_printf ("Import table size %d is smaller than 40", it.size));
586
587         ilt_rva = read32 (ptr);
588         if (ilt_rva && !bounds_check_virtual_address (ctx, ilt_rva, 8))
589                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Lookup Table rva %x", ilt_rva));
590
591         name_rva = read32 (ptr + 12);
592         if (name_rva && !bounds_check_virtual_address (ctx, name_rva, SIZE_OF_MSCOREE))
593                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name rva %x", name_rva));
594
595         iat_rva = read32 (ptr + 16);
596         if (iat_rva) {
597                 if (!bounds_check_virtual_address (ctx, iat_rva, 8))
598                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Address Table rva %x", iat_rva));
599
600                 if (iat_rva != ctx->data_directories [IAT_IDX].rva)
601                         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));
602         }
603
604         if (name_rva) {
605                 name_rva = translate_rva (ctx, name_rva);
606                 g_assert (name_rva != INVALID_OFFSET);
607                 ptr = ctx->data + name_rva;
608         
609                 if (memcmp ("mscoree.dll", ptr, SIZE_OF_MSCOREE)) {
610                         char name[SIZE_OF_MSCOREE];
611                         memcpy (name, ptr, SIZE_OF_MSCOREE);
612                         name [SIZE_OF_MSCOREE - 1] = 0;
613                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name: '%s'", name));
614                 }
615         }
616         
617         if (ilt_rva) {
618                 verify_hint_name_table (ctx, ilt_rva, "Import Lookup Table");
619                 CHECK_ERROR ();
620         }
621
622         if (iat_rva)
623                 verify_hint_name_table (ctx, iat_rva, "Import Address Table");
624 }
625
626 static void
627 verify_resources_table (VerifyContext *ctx)
628 {
629         DataDirectory it = ctx->data_directories [RESOURCE_TABLE_IDX];
630         guint32 offset;
631         guint16 named_entries, id_entries;
632         const char *ptr, *root, *end;
633
634         if (it.rva == 0)
635                 return;
636
637         if (it.size < 16)
638                 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));
639
640         offset = it.translated_offset;
641         root = ptr = ctx->data + offset;
642         end = root + it.size;
643
644         g_assert (offset != INVALID_OFFSET);
645
646         named_entries = read16 (ptr + 12);
647         id_entries = read16 (ptr + 14);
648
649         if ((named_entries + id_entries) * 8 + 16 > it.size)
650                 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));
651
652         /* XXX at least one unmanaged resource is added due to a call to AssemblyBuilder::DefineVersionInfoResource () 
653         if (named_entries || id_entries)
654                 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support full verification of PECOFF resources"));
655         */
656 }
657
658 /*----------nothing from here on can use data_directory---*/
659
660 static DataDirectory
661 get_data_dir (VerifyContext *ctx, int idx)
662 {
663         MonoCLIImageInfo *iinfo = ctx->image->image_info;
664         MonoPEDirEntry *entry= &iinfo->cli_header.datadir.pe_export_table;
665         DataDirectory res;
666
667         entry += idx;
668         res.rva = entry->rva;
669         res.size = entry->size;
670         res.translated_offset = translate_rva (ctx, res.rva);
671         return res;
672
673 }
674 static void
675 verify_cli_header (VerifyContext *ctx)
676 {
677         DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
678         guint32 offset;
679         const char *ptr;
680         int i;
681
682         if (it.rva == 0)
683                 ADD_ERROR (ctx, g_strdup_printf ("CLI header missing"));
684
685         if (it.size != 72)
686                 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size in data directory %d must be 72", it.size));
687
688         offset = it.translated_offset;
689         ptr = ctx->data + offset;
690
691         g_assert (offset != INVALID_OFFSET);
692
693         if (read16 (ptr) != 72)
694                 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size %d must be 72", read16 (ptr)));
695
696         if (!bounds_check_virtual_address (ctx, read32 (ptr + 8), read32 (ptr + 12)))
697                 ADD_ERROR (ctx, g_strdup_printf ("Invalid medatata section rva/size pair %x/%x", read32 (ptr + 8), read32 (ptr + 12)));
698
699
700         if (!read32 (ptr + 8) || !read32 (ptr + 12))
701                 ADD_ERROR (ctx, g_strdup_printf ("Missing medatata section in the CLI header"));
702
703         if ((read32 (ptr + 16) & ~0x0001000B) != 0)
704                 ADD_ERROR (ctx, g_strdup_printf ("Invalid CLI header flags"));
705
706         ptr += 24;
707         for (i = 0; i < 6; ++i) {
708                 guint32 rva = read32 (ptr);
709                 guint32 size = read32 (ptr + 4);
710
711                 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
712                         ADD_ERROR (ctx, g_strdup_printf ("Invalid cli section %i rva/size pair %x/%x", i, rva, size));
713
714                 ptr += 8;
715
716                 if (rva && i > 1)
717                         ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't support cli header section %d", i));
718         }
719 }
720
721 static guint32
722 pad4 (guint32 offset)
723 {
724         if (offset & 0x3) //pad to the next 4 byte boundary
725                 offset = (offset & ~0x3) + 4;
726         return offset;
727 }
728
729 static void
730 verify_metadata_header (VerifyContext *ctx)
731 {
732         int i;
733         DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
734         guint32 offset;
735         const char *ptr;
736
737         offset = it.translated_offset;
738         ptr = ctx->data + offset;
739         g_assert (offset != INVALID_OFFSET);
740
741         //build a directory entry for the metadata root
742         ptr += 8;
743         it.rva = read32 (ptr);
744         ptr += 4;
745         it.size = read32 (ptr);
746         it.translated_offset = offset = translate_rva (ctx, it.rva);
747
748         ptr = ctx->data + offset;
749         g_assert (offset != INVALID_OFFSET);
750
751         if (it.size < 20)
752                 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small %d (at least 20 bytes required for initial decoding)", it.size));
753
754         if (read32 (ptr) != 0x424A5342)
755                 ADD_ERROR (ctx, g_strdup_printf ("Invalid metadata signature, expected 0x424A5342 but got %08x", read32 (ptr)));
756
757         offset = pad4 (offset + 16 + read32 (ptr + 12));
758
759         if (!bounds_check_datadir (&it, offset, 4))
760                 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));
761
762         ptr = ctx->data + offset; //move to streams header 
763
764         if (read16 (ptr + 2) < 3)
765                 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section must have at least 3 streams (#~, #GUID and #Blob"));
766
767         ptr += 4;
768         offset += 4;
769
770         for (i = 0; i < 5; ++i) {
771                 guint32 stream_off, stream_size;
772                 int string_size, stream_idx;
773
774                 if (!bounds_check_datadir (&it, offset, 8))
775                         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));
776
777                 stream_off = it.translated_offset + read32 (ptr);
778                 stream_size = read32 (ptr + 4);
779
780                 if (!bounds_check_datadir (&it,  stream_off, stream_size))
781                         ADD_ERROR (ctx, g_strdup_printf ("Invalid stream header %d offset/size pair %x/%x", 0, stream_off, stream_size));
782
783                 ptr += 8;
784                 offset += 8;
785
786                 for (string_size = 0; string_size < 32; ++string_size) {
787                         if (!bounds_check_datadir (&it, offset++, 1))
788                                 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small to decode stream header %d name", i));
789                         if (!ptr [string_size])
790                                 break;
791                 }
792
793                 if (ptr [string_size])
794                         ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d name larger than 32 bytes", i));
795
796                 if (!strncmp ("#Strings", ptr, 9))
797                         stream_idx = STRINGS_STREAM;
798                 else if (!strncmp ("#US", ptr, 4))
799                         stream_idx = USER_STRINGS_STREAM;
800                 else if (!strncmp ("#Blob", ptr, 6))
801                         stream_idx = BLOB_STREAM;
802                 else if (!strncmp ("#GUID", ptr, 6))
803                         stream_idx = GUID_STREAM;
804                 else if (!strncmp ("#~", ptr, 3))
805                         stream_idx = TILDE_STREAM;
806                 else
807                         ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d invalid name %s", i, ptr));
808
809                 if (ctx->metadata_streams [stream_idx].offset != 0)
810                         ADD_ERROR (ctx, g_strdup_printf ("Duplicated metadata stream header %s", ptr));
811
812                 ctx->metadata_streams [stream_idx].offset = stream_off;
813                 ctx->metadata_streams [stream_idx].size = stream_size;
814
815                 offset = pad4 (offset);
816                 ptr = ctx->data + offset;
817         }
818
819         if (!ctx->metadata_streams [TILDE_STREAM].size)
820                 ADD_ERROR (ctx, g_strdup_printf ("Metadata #~ stream missing"));
821         if (!ctx->metadata_streams [GUID_STREAM].size)
822                 ADD_ERROR (ctx, g_strdup_printf ("Metadata guid stream missing"));
823         if (!ctx->metadata_streams [BLOB_STREAM].size)
824                 ADD_ERROR (ctx, g_strdup_printf ("Metadata blob stream missing"));
825                 
826 }
827
828 static void
829 verify_tables_schema (VerifyContext *ctx)
830 {
831         OffsetAndSize tables_area = ctx->metadata_streams [TILDE_STREAM];
832         unsigned offset = tables_area.offset;
833         const char *ptr = ctx->data + offset;
834         guint64 valid_tables;
835         guint32 count;
836         int i;
837
838         //printf ("tables_area size %d offset %x %s\n", tables_area.size, tables_area.offset, ctx->image->name);
839         if (tables_area.size < 24)
840                 ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for initial decoding (requires 24 bytes)", tables_area.size));
841
842         //printf ("ptr %x %x\n", ptr[4], ptr[5]);
843         if (ptr [4] != 2 && ptr [4] != 1)
844                 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata major version %d, expected 2", ptr [4]));
845         if (ptr [5] != 0)
846                 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata minor version %d, expected 0", ptr [5]));
847
848         if ((ptr [6] & ~0x7) != 0)
849                 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]));
850
851         valid_tables = read64 (ptr + 8);
852         count = 0;
853         for (i = 0; i < 64; ++i) {
854                 if (!(valid_tables & ((guint64)1 << i)))
855                         continue;
856
857                 /*MS Extensions: 0x3 0x5 0x7 0x13 0x16
858                   Unused: 0x1E 0x1F 0x2D-0x3F
859                   We don't care about the MS extensions.*/
860                 if (i == 0x3 || i == 0x5 || i == 0x7 || i == 0x13 || i == 0x16)
861                         ADD_ERROR (ctx, g_strdup_printf ("The metadata verifies doesn't support MS specific table %x", i));
862                 if (i == 0x1E || i == 0x1F || i >= 0x2D)
863                         ADD_ERROR (ctx, g_strdup_printf ("Invalid table %x", i));
864                 ++count;
865         }
866
867         if (tables_area.size < 24 + count * 4)
868                 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));
869         ptr += 24;
870
871         for (i = 0; i < 64; ++i) {
872                 if (valid_tables & ((guint64)1 << i)) {
873                         guint32 row_count = read32 (ptr);
874                         if (row_count > (1 << 24) - 1)
875                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Table %d row count: %d. Mono only supports 16777215 rows", i, row_count));
876                         ptr += 4;
877                 }
878         }
879 }
880
881 /*----------nothing from here on can use data_directory or metadata_streams ---*/
882
883 static guint32
884 get_col_offset (VerifyContext *ctx, int table, int column)
885 {
886         guint32 bitfield = ctx->image->tables [table].size_bitfield;
887         guint32 offset = 0;
888
889         while (column-- > 0)
890                 offset += mono_metadata_table_size (bitfield, column);
891
892         return offset;
893 }
894
895 static guint32
896 get_col_size (VerifyContext *ctx, int table, int column)
897 {
898         return mono_metadata_table_size (ctx->image->tables [table].size_bitfield, column);
899 }
900
901 static OffsetAndSize
902 get_metadata_stream (VerifyContext *ctx, MonoStreamHeader *header)
903 {
904         OffsetAndSize res;
905         res.offset = header->data - ctx->data;
906         res.size = header->size;
907
908         return res;
909 }
910
911 static gboolean
912 is_valid_string_full (VerifyContext *ctx, guint32 offset, gboolean allow_empty)
913 {
914         OffsetAndSize strings = get_metadata_stream (ctx, &ctx->image->heap_strings);
915         glong length;
916         const char *data = ctx->data + strings.offset;
917
918         if (offset >= strings.size)
919                 return FALSE;
920         if (data + offset < data) //FIXME, use a generalized and smart unsigned add with overflow check and fix the whole thing  
921                 return FALSE;
922
923         if (!mono_utf8_validate_and_len_with_bounds (data + offset, strings.size - offset, &length, NULL))
924                 return FALSE;
925         return allow_empty || length > 0;
926 }
927
928 static gboolean
929 is_valid_string (VerifyContext *ctx, guint32 offset)
930 {
931         return is_valid_string_full (ctx, offset, TRUE);
932 }
933
934 static gboolean
935 is_valid_non_empty_string (VerifyContext *ctx, guint32 offset)
936 {
937         return is_valid_string_full (ctx, offset, FALSE);
938 }
939
940 static gboolean
941 is_valid_guid (VerifyContext *ctx, guint32 offset)
942 {
943         OffsetAndSize guids = get_metadata_stream (ctx, &ctx->image->heap_guid);
944         return guids.size >= 8 && guids.size - 8 >= offset;
945 }
946
947 static guint32
948 get_coded_index_token (int token_kind, guint32 coded_token)
949 {
950         guint32 bits = coded_index_desc [token_kind];
951         return coded_token >> bits;
952 }
953
954 static guint32
955 get_coded_index_table (int kind, guint32 coded_token)
956 {
957         guint32 idx, bits = coded_index_desc [kind];
958         kind += 2;
959         idx = coded_token & ((1 << bits) - 1);
960         return coded_index_desc [kind + idx];
961 }
962
963 static guint32
964 make_coded_token (int kind, guint32 table, guint32 table_idx)
965 {
966         guint32 bits = coded_index_desc [kind++];
967         guint32 tables = coded_index_desc [kind++];
968         guint32 i;
969         for (i = 0; i < tables; ++i) {
970                 if (coded_index_desc [kind++] == table)
971                         return ((table_idx + 1) << bits) | i; 
972         }
973         g_assert_not_reached ();
974         return -1;
975 }
976
977 static gboolean
978 is_valid_coded_index (VerifyContext *ctx, int token_kind, guint32 coded_token)
979 {
980         guint32 bits = coded_index_desc [token_kind++];
981         guint32 table_count = coded_index_desc [token_kind++];
982         guint32 table = coded_token & ((1 << bits) - 1);
983         guint32 token = coded_token >> bits;
984
985         if (table >= table_count)
986                 return FALSE;
987
988         /*token_kind points to the first table idx*/
989         table = coded_index_desc [token_kind + table];
990
991         if (table == INVALID_TABLE)
992                 return FALSE;
993         return token <= ctx->image->tables [table].rows;
994 }
995
996 typedef struct {
997         guint32 token;
998         guint32 col_size;
999         guint32 col_offset;
1000         MonoTableInfo *table;
1001 } RowLocator;
1002
1003 static int
1004 token_locator (const void *a, const void *b)
1005 {
1006         RowLocator *loc = (RowLocator *)a;
1007         unsigned const char *row = (unsigned const char *)b;
1008         guint32 token = loc->col_size == 2 ? read16 (row + loc->col_offset) : read32 (row + loc->col_offset);
1009
1010         VERIFIER_DEBUG ( printf ("\tfound token %x at idx %d\n", token, ((const char*)row - loc->table->base) / loc->table->row_size) );
1011         return (int)loc->token - (int)token;
1012 }
1013
1014 static int
1015 search_sorted_table (VerifyContext *ctx, int table, int column, guint32 coded_token)
1016 {
1017         MonoTableInfo *tinfo = &ctx->image->tables [table];
1018         RowLocator locator;
1019         const char *res, *base;
1020         locator.token = coded_token;
1021         locator.col_offset = get_col_offset (ctx, table, column);
1022         locator.col_size = get_col_size (ctx, table, column);
1023         locator.table = tinfo;
1024
1025         base = tinfo->base;
1026
1027         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) );
1028         res = bsearch (&locator, base, tinfo->rows, tinfo->row_size, token_locator);
1029         if (!res)
1030                 return -1;
1031
1032         return (res - base) / tinfo->row_size;
1033 }
1034
1035 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1036 static const char*
1037 get_string_ptr (VerifyContext *ctx, guint offset)
1038 {
1039         return ctx->image->heap_strings.data + offset;
1040 }
1041
1042 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1043 static int
1044 string_cmp (VerifyContext *ctx, const char *str, guint offset)
1045 {
1046         if (offset == 0)
1047                 return strcmp (str, "");
1048
1049         return strcmp (str, get_string_ptr (ctx, offset));
1050 }
1051
1052 static gboolean
1053 mono_verifier_is_corlib (MonoImage *image)
1054 {
1055         gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ? 
1056                         TRUE : mono_security_core_clr_is_platform_image (image);
1057
1058         return trusted_location && image->module_name && !strcmp ("mscorlib.dll", image->module_name);
1059 }
1060
1061 static gboolean
1062 typedef_is_system_object (VerifyContext *ctx, guint32 *data)
1063 {
1064         return mono_verifier_is_corlib (ctx->image) && !string_cmp (ctx, "System", data [MONO_TYPEDEF_NAMESPACE]) && !string_cmp (ctx, "Object", data [MONO_TYPEDEF_NAME]);
1065 }
1066
1067 static gboolean
1068 decode_value (const char *_ptr, unsigned available, unsigned *value, unsigned *size)
1069 {
1070         unsigned char b;
1071         const unsigned char *ptr = (const unsigned char *)_ptr;
1072
1073         if (!available)
1074                 return FALSE;
1075
1076         b = *ptr;
1077         *value = *size = 0;
1078         
1079         if ((b & 0x80) == 0) {
1080                 *size = 1;
1081                 *value = b;
1082         } else if ((b & 0x40) == 0) {
1083                 if (available < 2)
1084                         return FALSE;
1085                 *size = 2;
1086                 *value = ((b & 0x3f) << 8 | ptr [1]);
1087         } else {
1088                 if (available < 4)
1089                         return FALSE;
1090                 *size = 4;
1091                 *value  = ((b & 0x1f) << 24) |
1092                         (ptr [1] << 16) |
1093                         (ptr [2] << 8) |
1094                         ptr [3];
1095         }
1096
1097         return TRUE;
1098 }
1099
1100 static gboolean
1101 decode_signature_header (VerifyContext *ctx, guint32 offset, int *size, const char **first_byte)
1102 {
1103         MonoStreamHeader blob = ctx->image->heap_blob;
1104         guint32 value, enc_size;
1105
1106         if (offset >= blob.size)
1107                 return FALSE;
1108
1109         if (!decode_value (blob.data + offset, blob.size - offset, &value, &enc_size))
1110                 return FALSE;
1111
1112         if (offset + enc_size + value < offset)
1113                 return FALSE;
1114
1115         if (offset + enc_size + value > blob.size)
1116                 return FALSE;
1117
1118         *size = value;
1119         *first_byte = blob.data + offset + enc_size;
1120         return TRUE;
1121 }
1122
1123 static gboolean
1124 safe_read (const char **_ptr, const char *limit, void *dest, int size)
1125 {
1126         const char *ptr = *_ptr;
1127         if (ptr + size > limit)
1128                 return FALSE;
1129         switch (size) {
1130         case 1:
1131                 *((guint8*)dest) = *((guint8*)ptr);
1132                 ++ptr;
1133                 break;
1134         case 2:
1135                 *((guint16*)dest) = read16 (ptr);
1136                 ptr += 2;
1137                 break;
1138         case 4:
1139                 *((guint32*)dest) = read32 (ptr);
1140                 ptr += 4;
1141                 break;
1142         }
1143         *_ptr = ptr;
1144         return TRUE;
1145 }
1146
1147 static gboolean
1148 safe_read_compressed_int (const char **_ptr, const char *limit, unsigned *dest)
1149 {
1150         unsigned size = 0;
1151         const char *ptr = *_ptr;
1152         gboolean res = decode_value (ptr, limit - ptr, dest, &size);
1153         *_ptr = ptr + size;
1154         return res;
1155 }
1156
1157 #define safe_read8(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 1)
1158 #define safe_read_cint(VAR, PTR, LIMIT) safe_read_compressed_int (&PTR, LIMIT, &VAR)
1159 #define safe_read16(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 2)
1160 #define safe_read32(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 4)
1161
1162 static gboolean
1163 parse_type (VerifyContext *ctx, const char **_ptr, const char *end);
1164
1165 static gboolean
1166 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged);
1167
1168 static gboolean
1169 parse_custom_mods (VerifyContext *ctx, const char **_ptr, const char *end)
1170 {
1171         const char *ptr = *_ptr;
1172         guint type = 0;
1173         guint32 token = 0;
1174
1175         while (TRUE) {
1176                 if (!safe_read8 (type, ptr, end))
1177                         FAIL (ctx, g_strdup ("CustomMod: Not enough room for the type"));
1178         
1179                 if (type != MONO_TYPE_CMOD_REQD && type != MONO_TYPE_CMOD_OPT) {
1180                         --ptr;
1181                         break;
1182                 }
1183         
1184                 if (!safe_read_cint (token, ptr, end))
1185                         FAIL (ctx, g_strdup ("CustomMod: Not enough room for the token"));
1186         
1187                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1188                         FAIL (ctx, g_strdup_printf ("CustomMod: invalid TypeDefOrRef token %x", token));
1189         }
1190
1191         *_ptr = ptr;
1192         return TRUE;
1193 }
1194
1195 static gboolean
1196 parse_array_shape (VerifyContext *ctx, const char **_ptr, const char *end)
1197 {
1198         const char *ptr = *_ptr;
1199         guint8 val;
1200         guint32 size, num, i;
1201
1202         if (!safe_read8 (val, ptr, end))
1203                 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for Rank"));
1204
1205         if (val == 0)
1206                 FAIL (ctx, g_strdup ("ArrayShape: Invalid shape with zero Rank"));
1207
1208         if (!safe_read_cint (size, ptr, end))
1209                 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumSizes"));
1210
1211         for (i = 0; i < size; ++i) {
1212                 if (!safe_read_cint (num, ptr, end))
1213                         FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for Size of rank %d", i + 1));
1214         }
1215
1216         if (!safe_read_cint (size, ptr, end))
1217                 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumLoBounds"));
1218
1219         for (i = 0; i < size; ++i) {
1220                 if (!safe_read_cint (num, ptr, end))
1221                         FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for LoBound of rank %d", i + 1));
1222         }
1223
1224         *_ptr = ptr;
1225         return TRUE;
1226 }
1227
1228 static gboolean
1229 parse_generic_inst (VerifyContext *ctx, const char **_ptr, const char *end)
1230 {
1231         const char *ptr = *_ptr;
1232         guint8 type;
1233         guint32 count, token, i;
1234
1235         if (!safe_read8 (type, ptr, end))
1236                 FAIL (ctx, g_strdup ("GenericInst: Not enough room for kind"));
1237
1238         if (type != MONO_TYPE_CLASS && type != MONO_TYPE_VALUETYPE)
1239                 FAIL (ctx, g_strdup_printf ("GenericInst: Invalid GenericInst kind %x\n", type));
1240
1241         if (!safe_read_cint (token, ptr, end))
1242                 FAIL (ctx, g_strdup ("GenericInst: Not enough room for type token"));
1243
1244         if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1245                 FAIL (ctx, g_strdup_printf ("GenericInst: invalid TypeDefOrRef token %x", token));
1246
1247         if (!safe_read_cint (count, ptr, end))
1248                 FAIL (ctx, g_strdup ("GenericInst: Not enough room for argument count"));
1249
1250         if (count == 0)
1251                 FAIL (ctx, g_strdup ("GenericInst: Zero arguments generic instance"));
1252
1253         for (i = 0; i < count; ++i) {
1254                 if (!parse_type (ctx, &ptr, end))
1255                         FAIL (ctx, g_strdup_printf ("GenericInst: invalid generic argument %d", i + 1));
1256         }
1257         *_ptr = ptr;
1258         return TRUE;
1259 }
1260
1261 static gboolean
1262 parse_type (VerifyContext *ctx, const char **_ptr, const char *end)
1263 {
1264         const char *ptr = *_ptr;
1265         guint8 type = 0;
1266         guint32 token = 0;
1267
1268         if (!safe_read8 (type, ptr, end))
1269                 FAIL (ctx, g_strdup ("Type: Not enough room for the type"));
1270
1271         if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_PTR) ||
1272                 (type >= MONO_TYPE_VALUETYPE && type <= MONO_TYPE_GENERICINST) ||
1273                 (type >= MONO_TYPE_I && type <= MONO_TYPE_U) ||
1274                 (type >= MONO_TYPE_FNPTR && type <= MONO_TYPE_MVAR)))
1275                 FAIL (ctx, g_strdup_printf ("Type: Invalid type kind %x\n", type));
1276
1277         switch (type) {
1278         case MONO_TYPE_PTR:
1279                 if (!parse_custom_mods (ctx, &ptr, end))
1280                         FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1281
1282                 if (!safe_read8 (type, ptr, end))
1283                         FAIL (ctx, g_strdup ("Type: Not enough room to parse the pointer type"));
1284
1285                 if (type != MONO_TYPE_VOID) {
1286                         --ptr;
1287                         if (!parse_type (ctx, &ptr, end))
1288                                 FAIL (ctx, g_strdup ("Type: Could not parse pointer type"));
1289                 }
1290                 break;
1291
1292         case MONO_TYPE_VALUETYPE:
1293         case MONO_TYPE_CLASS:
1294                 if (!safe_read_cint (token, ptr, end))
1295                         FAIL (ctx, g_strdup ("Type: Not enough room for the type token"));
1296         
1297                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
1298                         FAIL (ctx, g_strdup_printf ("Type: invalid TypeDefOrRef token %x", token));
1299                 break;
1300
1301         case MONO_TYPE_VAR:
1302         case MONO_TYPE_MVAR:
1303                 if (!safe_read_cint (token, ptr, end))
1304                         FAIL (ctx, g_strdup ("Type: Not enough room for to decode generic argument number"));
1305                 break;
1306
1307         case MONO_TYPE_ARRAY:
1308                 if (!parse_type (ctx, &ptr, end))
1309                         FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1310                 if (!parse_array_shape (ctx, &ptr, end))
1311                         FAIL (ctx, g_strdup ("Type: Could not parse array shape"));
1312                 break;
1313
1314         case MONO_TYPE_GENERICINST:
1315                 if (!parse_generic_inst (ctx, &ptr, end))
1316                         FAIL (ctx, g_strdup ("Type: Could not parse generic inst"));
1317                 break;
1318
1319         case MONO_TYPE_FNPTR:
1320                 if (!parse_method_signature (ctx, &ptr, end, TRUE, TRUE))
1321                         FAIL (ctx, g_strdup ("Type: Could not parse method pointer signature"));
1322                 break;
1323
1324         case MONO_TYPE_SZARRAY:
1325                 if (!parse_custom_mods (ctx, &ptr, end))
1326                         FAIL (ctx, g_strdup ("Type: Failed to parse array element custom attr"));
1327                 if (!parse_type (ctx, &ptr, end))
1328                         FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1329                 break;
1330         }
1331         *_ptr = ptr;
1332         return TRUE;
1333 }
1334
1335 static gboolean
1336 parse_return_type (VerifyContext *ctx, const char **_ptr, const char *end)
1337 {
1338         const char *ptr;
1339         int type = 0;
1340
1341         if (!parse_custom_mods (ctx, _ptr, end))
1342                 return FALSE;
1343
1344         ptr = *_ptr;
1345         if (!safe_read8 (type, ptr, end))
1346                 FAIL (ctx, g_strdup ("ReturnType: Not enough room for the type"));
1347
1348         if (type == MONO_TYPE_VOID || type == MONO_TYPE_TYPEDBYREF) {
1349                 *_ptr = ptr;
1350                 return TRUE;
1351         }
1352
1353         //it's a byref, update the cursor ptr
1354         if (type == MONO_TYPE_BYREF)
1355                 *_ptr = ptr;
1356
1357         return parse_type (ctx, _ptr, end);
1358 }
1359
1360 static gboolean
1361 parse_param (VerifyContext *ctx, const char **_ptr, const char *end)
1362 {
1363         const char *ptr;
1364         int type = 0;
1365
1366         if (!parse_custom_mods (ctx, _ptr, end))
1367                 return FALSE;
1368
1369         ptr = *_ptr;
1370         if (!safe_read8 (type, ptr, end))
1371                 FAIL (ctx, g_strdup ("Param: Not enough room for the type"));
1372
1373         if (type == MONO_TYPE_TYPEDBYREF) {
1374                 *_ptr = ptr;
1375                 return TRUE;
1376         }
1377
1378         //it's a byref, update the cursor ptr
1379         if (type == MONO_TYPE_BYREF)
1380                 *_ptr = ptr;
1381
1382         return parse_type (ctx, _ptr, end);
1383 }
1384
1385 static gboolean
1386 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged)
1387 {
1388         int cconv = 0;
1389         unsigned param_count = 0, gparam_count = 0, type = 0, i;
1390         const char *ptr = *_ptr;
1391         gboolean saw_sentinel = FALSE;
1392
1393         if (!safe_read8 (cconv, ptr, end))
1394                 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the call conv"));
1395
1396         if (cconv & 0x80)
1397                 FAIL (ctx, g_strdup ("MethodSig: CallConv has 0x80 set"));
1398
1399         if (allow_unmanaged) {
1400                 if ((cconv & 0x0F) > MONO_CALL_VARARG)
1401                         FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not valid, it's %x", cconv & 0x0F));
1402         } else if ((cconv & 0x0F) != MONO_CALL_DEFAULT && (cconv & 0x0F) != MONO_CALL_VARARG)
1403                 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not Default or Vararg, it's %x", cconv & 0x0F));
1404
1405         if ((cconv & 0x10) && !safe_read_cint (gparam_count, ptr, end))
1406                 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the generic param count"));
1407
1408         if ((cconv & 0x10) && gparam_count == 0)
1409                 FAIL (ctx, g_strdup ("MethodSig: Signature with generics but zero arity"));
1410
1411         if (allow_unmanaged && (cconv & 0x10))
1412                 FAIL (ctx, g_strdup ("MethodSig: Standalone signature with generic params"));
1413
1414         if (!safe_read_cint (param_count, ptr, end))
1415                 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the param count"));
1416
1417         if (!parse_return_type (ctx, &ptr, end))
1418                 FAIL (ctx, g_strdup ("MethodSig: Error parsing return type"));
1419
1420         for (i = 0; i < param_count; ++i) {
1421                 if (allow_sentinel) {
1422                         if (!safe_read8 (type, ptr, end))
1423                                 FAIL (ctx, g_strdup_printf ("MethodSig: Not enough room for param %d type", i));
1424
1425                         if (type == MONO_TYPE_SENTINEL) {
1426                                 if ((cconv & 0x0F) != MONO_CALL_VARARG)
1427                                         FAIL (ctx, g_strdup ("MethodSig: Found sentinel but signature is not vararg"));
1428
1429                                 if (saw_sentinel)
1430                                         FAIL (ctx, g_strdup ("MethodSig: More than one sentinel type"));
1431
1432                                 saw_sentinel = TRUE;
1433                         } else {
1434                                 --ptr;
1435                         }
1436                 }
1437
1438                 if (!parse_param (ctx, &ptr, end))
1439                         FAIL (ctx, g_strdup_printf ("MethodSig: Error parsing arg %d", i));
1440         }
1441
1442         *_ptr = ptr;
1443         return TRUE;
1444 }
1445
1446 static gboolean
1447 parse_property_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1448 {
1449         unsigned sig = 0;
1450         unsigned param_count = 0, i;
1451         const char *ptr = *_ptr;
1452
1453         if (!safe_read8 (sig, ptr, end))
1454                 FAIL (ctx, g_strdup ("PropertySig: Not enough room for signature"));
1455
1456         if (sig != 0x08 && sig != 0x28)
1457                 FAIL (ctx, g_strdup_printf ("PropertySig: Signature is not 0x28 or 0x08: %x", sig));
1458
1459         if (!safe_read_cint (param_count, ptr, end))
1460                 FAIL (ctx, g_strdup ("PropertySig: Not enough room for the param count"));
1461
1462         if (!parse_custom_mods (ctx, &ptr, end))
1463                 return FALSE;
1464
1465         if (!parse_type (ctx, &ptr, end))
1466                 FAIL (ctx, g_strdup ("PropertySig: Could not parse property type"));
1467
1468         for (i = 0; i < param_count; ++i) {
1469                 if (!parse_type (ctx, &ptr, end))
1470                         FAIL (ctx, g_strdup_printf ("PropertySig: Error parsing arg %d", i));
1471         }
1472
1473         *_ptr = ptr;
1474         return TRUE;
1475 }
1476
1477 static gboolean
1478 parse_field (VerifyContext *ctx, const char **_ptr, const char *end)
1479 {
1480         const char *ptr = *_ptr;
1481         guint8 signature = 0;
1482
1483         if (!safe_read8 (signature, ptr, end))
1484                 FAIL (ctx, g_strdup ("Field: Not enough room for field signature"));
1485
1486         if (signature != 0x06)
1487                 FAIL (ctx, g_strdup_printf ("Field: Invalid signature 0x%x, must be 6", signature));
1488         *_ptr = ptr; 
1489
1490         if (!parse_custom_mods (ctx, _ptr, end))
1491                 return FALSE;
1492
1493         return parse_type (ctx, _ptr, end);
1494 }
1495
1496 static gboolean
1497 parse_locals_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1498 {
1499         unsigned sig = 0;
1500         unsigned locals_count = 0, i;
1501         const char *ptr = *_ptr;        
1502
1503         if (!safe_read8 (sig, ptr, end))
1504                 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for signature"));
1505
1506         if (sig != 0x07)
1507                 FAIL (ctx, g_strdup_printf ("LocalsSig: Signature is not 0x28 or 0x08: %x", sig));
1508
1509         if (!safe_read_cint (locals_count, ptr, end))
1510                 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for the param count"));
1511
1512         if (locals_count == 0)
1513                 FAIL (ctx, g_strdup ("LocalsSig: Signature with zero locals"));
1514
1515         for (i = 0; i < locals_count; ++i) {
1516                 if (!safe_read8 (sig, ptr, end))
1517                         FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1518
1519                 if (sig == MONO_TYPE_TYPEDBYREF)
1520                         continue;
1521
1522                 while (sig == MONO_TYPE_CMOD_REQD || sig == MONO_TYPE_CMOD_OPT || sig == MONO_TYPE_PINNED) {
1523                         if (sig != MONO_TYPE_PINNED && !parse_custom_mods (ctx, &ptr, end))
1524                                 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1525                         if (!safe_read8 (sig, ptr, end))
1526                                 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1527                 }
1528                 --ptr;
1529                 if (!parse_type (ctx, &ptr, end))
1530                         FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1531         }
1532
1533         *_ptr = ptr;
1534         return TRUE;
1535 }
1536
1537 static gboolean
1538 is_valid_field_signature (VerifyContext *ctx, guint32 offset)
1539 {
1540         int size = 0, signature = 0;
1541         const char *ptr = NULL, *end;
1542
1543         if (!decode_signature_header (ctx, offset, &size, &ptr))
1544                 FAIL (ctx, g_strdup ("FieldSig: Could not decode signature header"));
1545         end = ptr + size;
1546
1547         if (!safe_read8 (signature, ptr, end))
1548                 FAIL (ctx, g_strdup ("FieldSig: Not enough room for the signature"));
1549
1550         if (signature != 6)
1551                 FAIL (ctx, g_strdup_printf ("FieldSig: Invalid signature %x", signature));
1552         --ptr;
1553
1554         return parse_field (ctx, &ptr, end);
1555 }
1556
1557 static gboolean
1558 is_valid_method_signature (VerifyContext *ctx, guint32 offset)
1559 {
1560         int size = 0;
1561         const char *ptr = NULL, *end;
1562
1563         if (!decode_signature_header (ctx, offset, &size, &ptr))
1564                 FAIL (ctx, g_strdup ("MethodSig: Could not decode signature header"));
1565         end = ptr + size;
1566
1567         return parse_method_signature (ctx, &ptr, end, FALSE, FALSE);
1568 }
1569
1570 static gboolean
1571 is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
1572 {
1573         int size = 0;
1574         unsigned signature = 0;
1575         const char *ptr = NULL, *end;
1576
1577         if (!decode_signature_header (ctx, offset, &size, &ptr))
1578                 FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
1579         end = ptr + size;
1580
1581         if (!safe_read8 (signature, ptr, end))
1582                 FAIL (ctx, g_strdup ("MemberRefSig: Not enough room for the call conv"));
1583         --ptr;
1584
1585         if (signature == 0x06)
1586                 return parse_field (ctx, &ptr, end);
1587
1588         return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1589 }
1590
1591 static gboolean
1592 is_vald_cattr_blob (VerifyContext *ctx, guint32 offset)
1593 {
1594         int size = 0;
1595         guint16 prolog = 0;
1596         const char *ptr = NULL, *end;
1597
1598         if (!offset)
1599                 return TRUE;
1600
1601         if (!decode_signature_header (ctx, offset, &size, &ptr))
1602                 FAIL (ctx, g_strdup ("CustomAttribute: Could not decode signature header"));
1603         end = ptr + size;
1604
1605         if (!safe_read16 (prolog, ptr, end))
1606                 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1607
1608         if (prolog != 1)
1609                 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1610                 
1611         return TRUE;
1612 }
1613
1614 static gboolean
1615 is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
1616 {
1617         OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1618         //TODO do proper verification
1619         return blob.size >= 1 && blob.size - 1 >= offset;
1620 }
1621
1622 static gboolean
1623 is_valid_permission_set (VerifyContext *ctx, guint32 offset)
1624 {
1625         OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1626         //TODO do proper verification
1627         return blob.size >= 1 && blob.size - 1 >= offset;
1628 }
1629
1630 static gboolean
1631 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
1632 {
1633         int size = 0;
1634         unsigned signature = 0;
1635         const char *ptr = NULL, *end;
1636
1637         if (!decode_signature_header (ctx, offset, &size, &ptr))
1638                 FAIL (ctx, g_strdup ("StandAloneSig: Could not decode signature header"));
1639         end = ptr + size;
1640
1641         if (!safe_read8 (signature, ptr, end))
1642                 FAIL (ctx, g_strdup ("StandAloneSig: Not enough room for the call conv"));
1643
1644         --ptr;
1645         if (signature == 0x07)
1646                 return parse_locals_signature (ctx, &ptr, end);
1647         return parse_method_signature (ctx, &ptr, end, TRUE, TRUE);
1648 }
1649
1650 static gboolean
1651 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
1652 {
1653         int size = 0;
1654         const char *ptr = NULL, *end;
1655
1656         if (!decode_signature_header (ctx, offset, &size, &ptr))
1657                 FAIL (ctx, g_strdup ("PropertySig: Could not decode signature header"));
1658         end = ptr + size;
1659
1660         return parse_property_signature (ctx, &ptr, end);
1661 }
1662
1663 static gboolean
1664 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
1665 {
1666         int size = 0;
1667         const char *ptr = NULL, *end;
1668         guint8 type = 0;
1669         
1670
1671         if (!decode_signature_header (ctx, offset, &size, &ptr))
1672                 FAIL (ctx, g_strdup ("TypeSpec: Could not decode signature header"));
1673         end = ptr + size;
1674
1675         if (!parse_custom_mods (ctx, &ptr, end))
1676                 return FALSE;
1677
1678         if (!safe_read8 (type, ptr, end))
1679                 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for type"));
1680         --ptr;
1681
1682         if (type == MONO_TYPE_TYPEDBYREF)
1683                 return TRUE;
1684
1685         return parse_type (ctx, &ptr, end);
1686 }
1687
1688 static gboolean
1689 is_valid_methodspec_blog (VerifyContext *ctx, guint32 offset)
1690 {
1691         int size = 0;
1692         const char *ptr = NULL, *end;
1693         guint8 type = 0;
1694         guint32 count = 0, i;
1695
1696         if (!decode_signature_header (ctx, offset, &size, &ptr))
1697                 FAIL (ctx, g_strdup ("MethodSpec: Could not decode signature header"));
1698         end = ptr + size;
1699
1700         if (!safe_read8 (type, ptr, end))
1701                 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for call convention"));
1702
1703         if (type != 0x0A)
1704                 FAIL (ctx, g_strdup_printf ("MethodSpec: Invalid call convention 0x%x, expected 0x0A", type));
1705
1706         if (!safe_read_cint (count, ptr, end))
1707                 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for parameter count"));
1708
1709         if (!count)
1710                 FAIL (ctx, g_strdup ("MethodSpec: Zero generic argument count"));
1711
1712         for (i = 0; i < count; ++i) {
1713                 if (!parse_type (ctx, &ptr, end))
1714                         FAIL (ctx, g_strdup_printf ("MethodSpec: Could not parse parameter %d", i + 1));
1715         }
1716         return TRUE;
1717 }
1718
1719 static gboolean
1720 is_valid_blob_object (VerifyContext *ctx, guint32 offset)
1721 {
1722         OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1723         guint32 entry_size, bytes;
1724
1725         if (blob.size < offset)
1726                 return FALSE;
1727
1728         if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1729                 return FALSE;
1730
1731         if (offset + entry_size + bytes < offset)
1732                 return FALSE;
1733
1734         return blob.size >= offset + entry_size + bytes;
1735 }
1736
1737 static gboolean
1738 is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
1739 {
1740         OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
1741         guint32 size, entry_size, bytes;
1742
1743         if (blob.size < offset)
1744                 return FALSE;
1745         
1746         if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
1747                 return FALSE;
1748
1749         if (type == MONO_TYPE_STRING) {
1750                 //String is encoded as: compressed_int:len len *chars
1751
1752                 offset += bytes;
1753                 if (offset > offset + entry_size * 2) //overflow
1754                         return FALSE;
1755                 offset += offset + entry_size * 2;
1756                 return  offset <= blob.size;
1757         }
1758
1759         switch (type) {
1760         case MONO_TYPE_BOOLEAN:
1761         case MONO_TYPE_I1:
1762         case MONO_TYPE_U1:
1763                 size = 1;
1764                 break;
1765         case MONO_TYPE_CHAR:
1766         case MONO_TYPE_I2:
1767         case MONO_TYPE_U2:
1768                 size = 2;
1769                 break;
1770         case MONO_TYPE_I4:
1771         case MONO_TYPE_U4:
1772         case MONO_TYPE_R4:
1773         case MONO_TYPE_CLASS:
1774                 size = 4;
1775                 break;
1776
1777         case MONO_TYPE_I8:
1778         case MONO_TYPE_U8:
1779         case MONO_TYPE_R8:
1780                 size = 8;
1781                 break;
1782         default:
1783                 g_assert_not_reached ();
1784         }
1785
1786         if (size != entry_size)
1787                 return FALSE;
1788         offset += bytes;
1789
1790         if(offset > offset + size) //overflow
1791                 return FALSE;
1792
1793         if (offset + size > blob.size)
1794                 return FALSE;
1795
1796         if (type == MONO_TYPE_CLASS && read32 (ctx->data + offset))
1797                 return FALSE;
1798         return TRUE;
1799 }
1800
1801 #define FAT_HEADER_INVALID_FLAGS ~(0x3 | 0x8 | 0x10 | 0xF000)
1802 //only 0x01, 0x40 and 0x80 are allowed
1803 #define SECTION_HEADER_INVALID_FLAGS 0x3E
1804
1805 static gboolean
1806 is_valid_method_header (VerifyContext *ctx, guint32 rva)
1807 {
1808         guint32 local_vars_tok, code_size, offset = mono_cli_rva_image_map (ctx->image, rva);
1809         guint8 header = 0;
1810         guint16 fat_header = 0, size = 0, max_stack;
1811         const char *ptr = NULL, *end;
1812
1813         if (offset == INVALID_ADDRESS)
1814                 FAIL (ctx, g_strdup ("MethodHeader: Invalid RVA"));
1815
1816         ptr = ctx->data + offset;
1817         end = ctx->data + ctx->size; /*no worries if it spawns multiple sections*/
1818
1819         if (!safe_read8 (header, ptr, end))
1820                 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for header"));
1821
1822         switch (header & 0x3) {
1823         case 0:
1824         case 1:
1825                 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid header type 0x%x", header & 0x3));
1826         case 2:
1827                 header >>= 2;
1828                 if (ADDP_IS_GREATER_OR_OVF (ptr, header, end)) 
1829                         FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for method body. Required %d, but only %d is available", header, end - ptr));
1830                 return TRUE;
1831         }
1832         //FAT HEADER
1833         --ptr;
1834         if (!safe_read16 (fat_header, ptr, end))
1835                 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for fat header"));
1836
1837         size = (fat_header >> 12) & 0xF;
1838         if (size != 3)
1839                 FAIL (ctx, g_strdup ("MethodHeader: header size must be 3"));
1840
1841         if (!safe_read16 (max_stack, ptr, end))
1842                 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for max stack"));
1843
1844         if (!safe_read32 (code_size, ptr, end))
1845                 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for code size"));
1846
1847         if (!safe_read32 (local_vars_tok, ptr, end))
1848                 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for local vars tok"));
1849
1850         if (local_vars_tok) {
1851                 if (((local_vars_tok >> 24) & 0xFF) != 0x11)
1852                         FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature table 0x%x", ((local_vars_tok >> 24) & 0xFF)));
1853                 if ((local_vars_tok & 0xFFFFFF) > ctx->image->tables [MONO_TABLE_STANDALONESIG].rows)   
1854                         FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature points to invalid row 0x%x", local_vars_tok & 0xFFFFFF));
1855         }
1856
1857         if (fat_header & FAT_HEADER_INVALID_FLAGS)
1858                 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid fat signature flags %x", fat_header & FAT_HEADER_INVALID_FLAGS));
1859
1860         if (ADDP_IS_GREATER_OR_OVF (ptr, code_size, end))
1861                 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for code %d", code_size));
1862
1863         if (!(fat_header & 0x08))
1864                 return TRUE;
1865
1866         ptr += code_size;
1867
1868         do {
1869                 guint32 section_header = 0, section_size = 0;
1870                 gboolean is_fat;
1871
1872                 ptr = dword_align (ptr);
1873                 if (!safe_read32 (section_header, ptr, end))
1874                         FAIL (ctx, g_strdup ("MethodHeader: Not enough room for data section header"));
1875
1876                 if (section_header & SECTION_HEADER_INVALID_FLAGS)
1877                         FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section header flags 0x%x", section_header & SECTION_HEADER_INVALID_FLAGS));
1878                         
1879                 is_fat = (section_header & METHOD_HEADER_SECTION_FAT_FORMAT) != 0;
1880                 section_size = (section_header >> 8) & (is_fat ? 0xFFFFFF : 0xFF);
1881
1882                 if (section_size < 4)
1883                         FAIL (ctx, g_strdup_printf ("MethodHeader: Section size too small"));
1884
1885                 if (ADDP_IS_GREATER_OR_OVF (ptr, section_size - 4, end)) /*must be section_size -4 as ptr was incremented by safe_read32*/
1886                         FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section content %d", section_size));
1887
1888                 if (section_header & METHOD_HEADER_SECTION_EHTABLE) {
1889                         guint32 i, clauses = (section_size - 4) / (is_fat ? 24 : 12);
1890                         if (clauses * (is_fat ? 24 : 12) + 4 != section_size)
1891                                 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid EH section size %d, it's not of the proper size", section_size));
1892
1893                         /* only verify the class token is verified as the rest is done by the IL verifier*/
1894                         for (i = 0; i < clauses; ++i) {
1895                                 guint32 class_token = 0;
1896                                 ptr += (is_fat ? 20 : 8);
1897                                 if (!safe_read32 (class_token, ptr, end))
1898                                         FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section %d", i));
1899                                 if (!*ptr == MONO_EXCEPTION_CLAUSE_NONE && class_token) {
1900                                         guint table = mono_metadata_token_table (class_token);
1901                                         if (table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPESPEC)
1902                                                 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token table %x", i, table));
1903                                         if (mono_metadata_token_index (class_token) > ctx->image->tables [table].rows)
1904                                                 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token index %x", i, mono_metadata_token_index (class_token)));
1905                                 }
1906                         }
1907                 }
1908
1909                 if (!(section_header & METHOD_HEADER_SECTION_MORE_SECTS))
1910                         break;
1911         } while (1);
1912         return TRUE;
1913 }
1914
1915 static void
1916 verify_module_table (VerifyContext *ctx)
1917 {
1918         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
1919         guint32 data [MONO_MODULE_SIZE];
1920
1921         if (table->rows != 1)
1922                 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
1923
1924         mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
1925
1926         if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
1927                 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
1928
1929         if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
1930                 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
1931
1932         if (data [MONO_MODULE_ENC] != 0)
1933                 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
1934
1935         if (data [MONO_MODULE_ENCBASE] != 0)
1936                 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
1937 }
1938
1939 static void
1940 verify_typeref_table (VerifyContext *ctx)
1941 {
1942         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
1943         guint32 data [MONO_TYPEREF_SIZE];
1944         int i;
1945
1946         for (i = 0; i < table->rows; ++i) {
1947                 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
1948                 if (!is_valid_coded_index (ctx, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1949                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d coded index 0x%08x", i, data [MONO_TYPEREF_SCOPE]));
1950                 
1951                 if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
1952                         ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", i));
1953
1954                 if (!data [MONO_TYPEREF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAME]))
1955                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d name token 0x%08x", i, data [MONO_TYPEREF_NAME]));
1956
1957                 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
1958                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d namespace token 0x%08x", i, data [MONO_TYPEREF_NAMESPACE]));
1959         }
1960 }
1961
1962 /*bits 9,11,14,15,19,21,24-31 */
1963 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 14) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
1964 static void
1965 verify_typedef_table (VerifyContext *ctx)
1966 {
1967         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
1968         guint32 data [MONO_TYPEDEF_SIZE];
1969         guint32 fieldlist = 1, methodlist = 1;
1970         int i;
1971
1972         if (table->rows == 0)
1973                 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
1974
1975         for (i = 0; i < table->rows; ++i) {
1976                 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
1977                 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
1978                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
1979
1980                 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
1981                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
1982
1983                 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
1984                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
1985
1986                 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
1987                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
1988
1989                 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
1990                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
1991
1992                 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
1993                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
1994
1995                 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
1996                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
1997
1998                 if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
1999                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
2000
2001                 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
2002                         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));
2003
2004                 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
2005                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
2006
2007                 if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
2008                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
2009
2010                 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
2011                         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));
2012
2013
2014                 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
2015                 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
2016         }
2017 }
2018
2019 static void
2020 verify_typedef_table_full (VerifyContext *ctx)
2021 {
2022         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2023         guint32 data [MONO_TYPEDEF_SIZE];
2024         int i;
2025
2026         if (table->rows == 0)
2027                 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2028
2029         for (i = 0; i < table->rows; ++i) {
2030                 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2031
2032                 if (i == 0) {
2033                         if (data [MONO_TYPEDEF_EXTENDS] != 0)
2034                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
2035                         continue;
2036                 }
2037
2038                 if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
2039                         if (data [MONO_TYPEDEF_EXTENDS])
2040                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
2041                         if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
2042                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
2043                 } else {
2044                         if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
2045                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
2046                 }
2047
2048                 if (!(data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE)) {
2049                         gboolean is_sys_obj = typedef_is_system_object (ctx, data);
2050                         gboolean has_parent = get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]) != 0;
2051
2052                         if (is_sys_obj) {
2053                                 if (has_parent)
2054                                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
2055                         } else {
2056                                 if (!has_parent) {
2057                                         ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
2058                                 }
2059                         }
2060                 }
2061         }
2062 }
2063
2064 /*bits 3,11,14 */
2065 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
2066 static void
2067 verify_field_table (VerifyContext *ctx)
2068 {
2069         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2070         guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
2071         int i;
2072
2073         module_field_list = (guint32)-1;
2074         if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2075                 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2076                 module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
2077         }
2078         
2079         for (i = 0; i < table->rows; ++i) {
2080                 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2081                 flags = data [MONO_FIELD_FLAGS];
2082
2083                 if (flags & INVALID_FIELD_FLAG_BITS)
2084                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
2085
2086                 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)         
2087                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
2088
2089                 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
2090                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
2091
2092                 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
2093                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
2094
2095                 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
2096                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
2097
2098                 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
2099                                 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
2100                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
2101
2102                 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
2103                                 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2104                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2105
2106                 if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
2107                                 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2108                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
2109
2110                 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
2111                                 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
2112                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2113
2114                 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
2115                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
2116
2117                 //TODO verify contant flag
2118
2119                 if (i + 1 < module_field_list) {
2120                         guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
2121                         if (!(flags & FIELD_ATTRIBUTE_STATIC))
2122                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
2123                         if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
2124                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
2125                 }
2126         }
2127 }
2128
2129 static void
2130 verify_field_table_full (VerifyContext *ctx)
2131 {
2132         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2133         guint32 data [MONO_FIELD_SIZE];
2134         int i;
2135         
2136         for (i = 0; i < table->rows; ++i) {
2137                 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2138
2139                 if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
2140                         ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
2141         }
2142 }
2143
2144 /*bits 6,8,9,10,11,13,14,15*/
2145 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 6) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
2146 static void
2147 verify_method_table (VerifyContext *ctx)
2148 {
2149         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2150         guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
2151         guint32 paramlist = 1;
2152         gboolean is_ctor, is_cctor;
2153         const char *name;
2154         int i;
2155
2156         module_method_list = (guint32)-1;
2157         if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2158                 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2159                 module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
2160         }
2161
2162         for (i = 0; i < table->rows; ++i) {
2163                 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2164                 rva = data [MONO_METHOD_RVA];
2165                 implflags = data [MONO_METHOD_IMPLFLAGS];
2166                 flags = data [MONO_METHOD_FLAGS];
2167                 access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
2168                 code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
2169                 
2170
2171                 if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
2172                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
2173
2174                 if (access == 0x7)
2175                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
2176
2177                 if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
2178                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
2179
2180                 name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
2181                 is_ctor = !strcmp (".ctor", name);
2182                 is_cctor = !strcmp (".cctor", name);
2183
2184                 if ((is_ctor || is_cctor) &&
2185                         search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
2186                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
2187
2188                 if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
2189                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
2190                 
2191                 if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
2192                         if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
2193                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
2194                         if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
2195                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
2196                 }
2197
2198                 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
2199                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
2200
2201                 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
2202                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
2203
2204                 //XXX no checks against cas stuff 10,11,12,13)
2205
2206                 //TODO check iface with .ctor (15,16)
2207
2208                 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
2209                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
2210
2211                 if (i + 1 < module_method_list) {
2212                         if (!(flags & METHOD_ATTRIBUTE_STATIC))
2213                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
2214                         if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
2215                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
2216                         if (!(access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED || access == METHOD_ATTRIBUTE_PUBLIC || access == METHOD_ATTRIBUTE_PRIVATE))
2217                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public or Private", i));
2218                 }
2219
2220                 //TODO check valuetype for synchronized
2221
2222                 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
2223                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
2224
2225                 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && (flags & METHOD_ATTRIBUTE_VIRTUAL))
2226                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
2227
2228                 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && 
2229                                 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2230                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
2231
2232                 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
2233                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
2234
2235                 //TODO check signature contents
2236
2237                 if (rva) {
2238                         if (flags & METHOD_ATTRIBUTE_ABSTRACT)
2239                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", i));
2240                         if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
2241                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
2242                 } else {
2243                         if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2244                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
2245                 }
2246
2247                 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2248                         if (rva)
2249                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
2250                         if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
2251                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
2252                 }
2253                 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
2254                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
2255
2256                 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
2257                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
2258
2259                 if (data [MONO_METHOD_PARAMLIST] == 0)
2260                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
2261
2262                 if (data [MONO_METHOD_PARAMLIST] < paramlist)
2263                         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));
2264
2265                 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
2266                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
2267
2268                 paramlist = data [MONO_METHOD_PARAMLIST];
2269
2270         }
2271 }
2272
2273 static void
2274 verify_method_table_full (VerifyContext *ctx)
2275 {
2276         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2277         guint32 data [MONO_METHOD_SIZE], rva;
2278         int i;
2279
2280         for (i = 0; i < table->rows; ++i) {
2281                 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2282                 rva = data [MONO_METHOD_RVA];
2283                 
2284                 if (rva && !is_valid_method_header (ctx, rva))
2285                         ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
2286         }
2287 }
2288
2289 static guint32
2290 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
2291 {
2292         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2293         guint32 row = *current_method;
2294         guint32 paramlist, tmp;
2295
2296
2297         paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
2298         while (row < table->rows) {
2299                 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
2300                 if (tmp > paramlist) {
2301                         *current_method = row;
2302                         return tmp - paramlist;
2303                 }
2304                 ++row;
2305         }
2306
2307         /*no more methods, all params apply to the last one*/
2308         *current_method = table->rows;
2309         return (guint32)-1;
2310 }
2311
2312
2313 #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))
2314 static void
2315 verify_param_table (VerifyContext *ctx)
2316 {
2317         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
2318         guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
2319         gboolean first_param = TRUE;
2320         int i;
2321
2322         remaining_params = get_next_param_count (ctx, &current_method);
2323
2324         for (i = 0; i < table->rows; ++i) {
2325                 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
2326                 flags = data [MONO_PARAM_FLAGS];
2327
2328                 if (flags & INVALID_PARAM_FLAGS_BITS)
2329                         ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
2330
2331                 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
2332                         if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
2333                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
2334                 } else {
2335                         if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
2336                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
2337                 }
2338
2339                 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)
2340                         ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
2341
2342                 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
2343                         ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
2344
2345                 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
2346                                 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
2347
2348                 first_param = FALSE;
2349                 sequence = data [MONO_PARAM_SEQUENCE];
2350                 if (--remaining_params == 0) {
2351                         remaining_params = get_next_param_count (ctx, &current_method);
2352                         first_param = TRUE;
2353                 }
2354         }
2355 }
2356
2357 static void
2358 verify_interfaceimpl_table (VerifyContext *ctx)
2359 {
2360         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
2361         guint32 data [MONO_INTERFACEIMPL_SIZE];
2362         int i;
2363
2364         for (i = 0; i < table->rows; ++i) {
2365                 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
2366                 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2367                         ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2368
2369                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2370                         ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
2371
2372                 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2373                         ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
2374         }
2375 }
2376
2377 static void
2378 verify_memberref_table (VerifyContext *ctx)
2379 {
2380         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2381         guint32 data [MONO_MEMBERREF_SIZE];
2382         int i;
2383
2384         for (i = 0; i < table->rows; ++i) {
2385                 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2386
2387                 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2388                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
2389
2390                 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2391                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
2392
2393                 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
2394                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
2395         }
2396 }
2397
2398
2399 static void
2400 verify_memberref_table_full (VerifyContext *ctx)
2401 {
2402         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2403         guint32 data [MONO_MEMBERREF_SIZE];
2404         int i;
2405
2406         for (i = 0; i < table->rows; ++i) {
2407                 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2408
2409                 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
2410                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field  0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
2411         }
2412 }
2413
2414 static void
2415 verify_constant_table (VerifyContext *ctx)
2416 {
2417         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
2418         guint32 data [MONO_CONSTANT_SIZE], type;
2419         int i;
2420
2421         for (i = 0; i < table->rows; ++i) {
2422                 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
2423                 type = data [MONO_CONSTANT_TYPE];
2424
2425                 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
2426                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
2427
2428                 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2429                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
2430
2431                 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2432                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
2433
2434                 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
2435                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
2436         }
2437 }
2438
2439 static void
2440 verify_cattr_table (VerifyContext *ctx)
2441 {
2442         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2443         guint32 data [MONO_CUSTOM_ATTR_SIZE];
2444         int i;
2445
2446         for (i = 0; i < table->rows; ++i) {
2447                 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2448
2449                 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
2450                         ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2451
2452                 if (!is_valid_coded_index (ctx, CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]))
2453                         ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2454         }
2455 }
2456
2457 static void
2458 verify_cattr_table_full (VerifyContext *ctx)
2459 {
2460         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2461         guint32 data [MONO_CUSTOM_ATTR_SIZE];
2462         int i;
2463
2464         for (i = 0; i < table->rows; ++i) {
2465                 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2466
2467                 if (!is_vald_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
2468                         ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2469         }
2470 }
2471
2472 static void
2473 verify_field_marshal_table (VerifyContext *ctx)
2474 {
2475         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2476         guint32 data [MONO_FIELD_MARSHAL_SIZE];
2477         int i;
2478
2479         for (i = 0; i < table->rows; ++i) {
2480                 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2481
2482                 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2483                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
2484
2485                 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
2486                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
2487
2488                 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
2489                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
2490         }
2491 }
2492
2493 static void
2494 verify_field_marshal_table_full (VerifyContext *ctx)
2495 {
2496         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2497         guint32 data [MONO_FIELD_MARSHAL_SIZE];
2498         int i;
2499
2500         for (i = 0; i < table->rows; ++i) {
2501                 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2502
2503                 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
2504                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
2505         }
2506 }
2507
2508 static void
2509 verify_decl_security_table (VerifyContext *ctx)
2510 {
2511         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2512         guint32 data [MONO_DECL_SECURITY_SIZE];
2513         int i;
2514
2515         for (i = 0; i < table->rows; ++i) {
2516                 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2517
2518                 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2519                         ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
2520
2521                 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
2522                         ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
2523
2524                 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
2525                         ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
2526         }
2527 }
2528
2529 static void
2530 verify_decl_security_table_full (VerifyContext *ctx)
2531 {
2532         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
2533         guint32 data [MONO_DECL_SECURITY_SIZE];
2534         int i;
2535
2536         for (i = 0; i < table->rows; ++i) {
2537                 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
2538
2539                 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
2540                         ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
2541         }
2542 }
2543
2544 static void
2545 verify_class_layout_table (VerifyContext *ctx)
2546 {
2547         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
2548         guint32 data [MONO_CLASS_LAYOUT_SIZE];
2549         int i;
2550
2551         for (i = 0; i < table->rows; ++i) {
2552                 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
2553
2554                 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2555                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
2556
2557                 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
2558                 case 0:
2559                 case 1:
2560                 case 2:
2561                 case 4:
2562                 case 8:
2563                 case 16:
2564                 case 32:
2565                 case 64:
2566                 case 128:
2567                         break;
2568                 default:
2569                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
2570                 }
2571         }
2572 }
2573
2574 static void
2575 verify_field_layout_table (VerifyContext *ctx)
2576 {
2577         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
2578         guint32 data [MONO_FIELD_LAYOUT_SIZE];
2579         int i;
2580
2581         for (i = 0; i < table->rows; ++i) {
2582                 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
2583
2584                 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2585                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
2586         }
2587 }
2588
2589 static void
2590 verify_standalonesig_table_full (VerifyContext *ctx)
2591 {
2592         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
2593         guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
2594         int i;
2595
2596         for (i = 0; i < table->rows; ++i) {
2597                 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
2598
2599                 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
2600                         ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
2601         }
2602 }
2603
2604 static void
2605 verify_eventmap_table (VerifyContext *ctx)
2606 {
2607         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
2608         guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
2609         int i;
2610
2611         for (i = 0; i < table->rows; ++i) {
2612                 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
2613
2614                 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2615                         ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
2616
2617                 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
2618                         ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
2619
2620                 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
2621         }
2622 }
2623
2624 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
2625 static void
2626 verify_event_table (VerifyContext *ctx)
2627 {
2628         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
2629         MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
2630         guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
2631         gboolean found_add, found_remove;
2632         int i, idx;
2633
2634         for (i = 0; i < table->rows; ++i) {
2635                 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
2636
2637                 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
2638                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
2639
2640                 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
2641                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
2642
2643                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
2644                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
2645
2646                 //check for Add and Remove
2647                 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
2648                 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
2649                 if (idx == -1)
2650                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
2651
2652                 //first we move to the first row for this event
2653                 while (idx > 0) {
2654                         if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
2655                                 break;
2656                         --idx;
2657                 }
2658                 //now move forward looking for AddOn and RemoveOn rows
2659                 found_add = found_remove = FALSE;
2660                 while (idx < sema_table->rows) {
2661                         mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
2662                         if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
2663                                 break;
2664                         if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
2665                                 found_add = TRUE;
2666                         if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
2667                                 found_remove = TRUE;
2668                         if (found_add && found_remove)
2669                                 break;
2670                         ++idx;
2671                 }
2672
2673                 if (!found_add)
2674                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2675                 if (!found_remove)
2676                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
2677         }
2678 }
2679
2680 static void
2681 verify_propertymap_table (VerifyContext *ctx)
2682 {
2683         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
2684         guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
2685         int i;
2686
2687         for (i = 0; i < table->rows; ++i) {
2688                 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
2689
2690                 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2691                         ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
2692
2693                 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
2694                         ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
2695
2696                 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
2697         }
2698 }
2699
2700 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
2701 static void
2702 verify_property_table (VerifyContext *ctx)
2703 {
2704         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
2705         guint32 data [MONO_PROPERTY_SIZE];
2706         int i;
2707
2708         for (i = 0; i < table->rows; ++i) {
2709                 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
2710
2711                 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
2712                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
2713
2714                 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
2715                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
2716
2717                 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
2718                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
2719
2720                 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
2721                                 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
2722                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
2723
2724         }
2725 }
2726
2727 static void
2728 verify_methodimpl_table (VerifyContext *ctx)
2729 {
2730         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
2731         guint32 data [MONO_METHODIMPL_SIZE];
2732         int i;
2733
2734         for (i = 0; i < table->rows; ++i) {
2735                 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
2736
2737                 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
2738                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2739                         
2740                 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2741                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2742                 
2743                 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
2744                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
2745
2746                 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2747                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2748                 
2749                 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
2750                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
2751         }
2752 }
2753
2754 static void
2755 verify_moduleref_table (VerifyContext *ctx)
2756 {
2757         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
2758         guint32 data [MONO_MODULEREF_SIZE];
2759         int i;
2760
2761         for (i = 0; i < table->rows; ++i) {
2762                 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
2763
2764                 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
2765                         ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
2766         }
2767 }
2768
2769 static void
2770 verify_typespec_table (VerifyContext *ctx)
2771 {
2772         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
2773         guint32 data [MONO_TYPESPEC_SIZE];
2774         int i;
2775
2776         for (i = 0; i < table->rows; ++i) {
2777                 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
2778
2779                 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
2780                         ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
2781         }
2782 }
2783
2784 #define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 6) | (1 << 8) | (1 << 9) | (1 << 10))
2785 static void
2786 verify_implmap_table (VerifyContext *ctx)
2787 {
2788         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
2789         guint32 data [MONO_IMPLMAP_SIZE], cconv;
2790         int i;
2791
2792         for (i = 0; i < table->rows; ++i) {
2793                 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
2794
2795                 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
2796                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
2797
2798                 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
2799                 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
2800                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
2801
2802                 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2803                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
2804
2805                 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
2806                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
2807
2808                 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
2809                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
2810
2811                 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
2812                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
2813
2814                 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULEREF].rows + 1)
2815                         ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
2816         }
2817 }
2818
2819 static void
2820 verify_fieldrva_table (VerifyContext *ctx)
2821 {
2822         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
2823         guint32 data [MONO_FIELD_RVA_SIZE];
2824         int i;
2825
2826         for (i = 0; i < table->rows; ++i) {
2827                 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
2828
2829                 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
2830                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
2831
2832                 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2833                         ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
2834         }
2835 }
2836
2837 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 8) | (1 << 14) | (1 << 15))
2838 static void
2839 verify_assembly_table (VerifyContext *ctx)
2840 {
2841         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
2842         guint32 data [MONO_ASSEMBLY_SIZE], hash;
2843         int i;
2844
2845         if (table->rows > 1)
2846                 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
2847
2848         for (i = 0; i < table->rows; ++i) {
2849                 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
2850
2851                 hash = data [MONO_ASSEMBLY_HASH_ALG];
2852                 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
2853                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
2854
2855                 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
2856                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2857
2858                 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY]))
2859                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
2860
2861                 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
2862                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
2863
2864                 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
2865                         ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
2866         }
2867 }
2868
2869 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~(1)
2870 static void
2871 verify_assemblyref_table (VerifyContext *ctx)
2872 {
2873         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
2874         guint32 data [MONO_ASSEMBLYREF_SIZE];
2875         int i;
2876
2877         for (i = 0; i < table->rows; ++i) {
2878                 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
2879
2880                 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
2881                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
2882
2883                 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY]))
2884                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
2885
2886                 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
2887                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
2888
2889                 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
2890                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
2891
2892                 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE]))
2893                         ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
2894         }
2895 }
2896
2897 #define INVALID_FILE_FLAGS_BITS ~(1)
2898 static void
2899 verify_file_table (VerifyContext *ctx)
2900 {
2901         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
2902         guint32 data [MONO_FILE_SIZE];
2903         int i;
2904
2905         for (i = 0; i < table->rows; ++i) {
2906                 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
2907                 
2908                 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
2909                         ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
2910
2911                 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
2912                         ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
2913
2914                 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE]))
2915                         ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
2916         }
2917 }
2918
2919 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
2920 static void
2921 verify_exportedtype_table (VerifyContext *ctx)
2922 {
2923         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
2924         guint32 data [MONO_EXP_TYPE_SIZE];
2925         int i;
2926
2927         for (i = 0; i < table->rows; ++i) {
2928                 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
2929                 
2930                 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
2931                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
2932
2933                 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
2934                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
2935
2936                 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
2937                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
2938
2939                 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
2940                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
2941
2942                 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
2943                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
2944
2945                 /*nested type can't have a namespace*/
2946                 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
2947                         ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
2948         }
2949 }
2950
2951 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
2952 static void
2953 verify_manifest_resource_table (VerifyContext *ctx)
2954 {
2955         MonoCLIImageInfo *iinfo = ctx->image->image_info;
2956         MonoCLIHeader *ch = &iinfo->cli_cli_header;
2957         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
2958         guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
2959         int i;
2960
2961         resources_size = ch->ch_resources.size;
2962
2963         for (i = 0; i < table->rows; ++i) {
2964                 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
2965
2966                 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
2967                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
2968
2969                 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
2970                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
2971
2972                 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
2973                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
2974
2975                 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
2976                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
2977
2978                 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
2979                 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
2980
2981                 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
2982                         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])));
2983
2984                 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
2985                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
2986
2987                 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
2988                         ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
2989         }
2990 }
2991
2992 static void
2993 verify_nested_class_table (VerifyContext *ctx)
2994 {
2995         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
2996         guint32 data [MONO_NESTED_CLASS_SIZE];
2997         int i;
2998
2999         for (i = 0; i < table->rows; ++i) {
3000                 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
3001
3002                 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3003                         ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
3004                 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3005                         ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3006                 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
3007                         ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass  and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3008         }
3009 }
3010
3011 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
3012 static void
3013 verify_generic_param_table (VerifyContext *ctx)
3014 {
3015         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
3016         guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
3017         int i, param_number = 0;
3018
3019         for (i = 0; i < table->rows; ++i) {
3020                 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
3021
3022                 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
3023                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
3024
3025                 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
3026                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
3027
3028                 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
3029                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
3030
3031                 token = data [MONO_GENERICPARAM_OWNER];
3032
3033                 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
3034                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
3035
3036                 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
3037                         ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
3038
3039                 if (token != last_token) {
3040                         param_number = 0;
3041                         last_token = token;
3042                 }
3043
3044                 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
3045                         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));
3046
3047                 ++param_number;
3048         }
3049 }
3050
3051 static void
3052 verify_method_spec_table (VerifyContext *ctx)
3053 {
3054         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3055         guint32 data [MONO_METHODSPEC_SIZE];
3056         int i;
3057
3058         for (i = 0; i < table->rows; ++i) {
3059                 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3060
3061                 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3062                         ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
3063
3064                 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3065                         ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
3066
3067                 if (!is_valid_methodspec_blog (ctx, data [MONO_METHODSPEC_SIGNATURE]))
3068                         ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3069         }
3070 }
3071
3072 static void
3073 verify_generic_param_constraint_table (VerifyContext *ctx)
3074 {
3075         MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
3076         guint32 data [MONO_GENPARCONSTRAINT_SIZE];
3077         int i;
3078
3079         for (i = 0; i < table->rows; ++i) {
3080                 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
3081
3082                 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
3083                         ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_TABLE_GENERICPARAM]));
3084
3085                 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3086                         ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
3087
3088                 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3089                         ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
3090         }
3091 }
3092
3093 static void
3094 verify_tables_data (VerifyContext *ctx)
3095 {
3096         OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
3097         guint32 size = 0, tables_offset;
3098         int i;
3099
3100         for (i = 0; i < 0x2D; ++i) {
3101                 MonoTableInfo *table = &ctx->image->tables [i];
3102                 guint32 tmp_size;
3103                 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
3104                 if (tmp_size < size) {
3105                         size = 0;
3106                         break;
3107                 }
3108                 size = tmp_size;                        
3109         }
3110
3111         if (size == 0)
3112                 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
3113
3114         tables_offset = ctx->image->tables_base - ctx->data;
3115         if (!bounds_check_offset (&tables_area, tables_offset, size))
3116                 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)));
3117
3118         verify_module_table (ctx);
3119         CHECK_ERROR ();
3120         verify_typeref_table (ctx);
3121         CHECK_ERROR ();
3122         verify_typedef_table (ctx);
3123         CHECK_ERROR ();
3124         verify_field_table (ctx);
3125         CHECK_ERROR ();
3126         verify_method_table (ctx);
3127         CHECK_ERROR ();
3128         verify_param_table (ctx);
3129         CHECK_ERROR ();
3130         verify_interfaceimpl_table (ctx);
3131         CHECK_ERROR ();
3132         verify_memberref_table (ctx);
3133         CHECK_ERROR ();
3134         verify_constant_table (ctx);
3135         CHECK_ERROR ();
3136         verify_cattr_table (ctx);
3137         CHECK_ERROR ();
3138         verify_field_marshal_table (ctx);
3139         CHECK_ERROR ();
3140         verify_decl_security_table (ctx);
3141         CHECK_ERROR ();
3142         verify_class_layout_table (ctx);
3143         CHECK_ERROR ();
3144         verify_field_layout_table (ctx);
3145         CHECK_ERROR ();
3146         verify_eventmap_table (ctx);
3147         CHECK_ERROR ();
3148         verify_event_table (ctx);
3149         CHECK_ERROR ();
3150         verify_propertymap_table (ctx);
3151         CHECK_ERROR ();
3152         verify_property_table (ctx);
3153         CHECK_ERROR ();
3154         verify_methodimpl_table (ctx);
3155         CHECK_ERROR ();
3156         verify_moduleref_table (ctx);
3157         CHECK_ERROR ();
3158         verify_typespec_table (ctx);
3159         CHECK_ERROR ();
3160         verify_implmap_table (ctx);
3161         CHECK_ERROR ();
3162         verify_fieldrva_table (ctx);
3163         CHECK_ERROR ();
3164         verify_assembly_table (ctx);
3165         CHECK_ERROR ();
3166         verify_assemblyref_table (ctx);
3167         CHECK_ERROR ();
3168         verify_file_table (ctx);
3169         CHECK_ERROR ();
3170         verify_exportedtype_table (ctx);
3171         CHECK_ERROR ();
3172         verify_manifest_resource_table (ctx);
3173         CHECK_ERROR ();
3174         verify_nested_class_table (ctx);
3175         CHECK_ERROR ();
3176         verify_generic_param_table (ctx);
3177         CHECK_ERROR ();
3178         verify_method_spec_table (ctx);
3179         CHECK_ERROR ();
3180         verify_generic_param_constraint_table (ctx);
3181 }
3182
3183 static void
3184 init_verify_context (VerifyContext *ctx, MonoImage *image, GSList **error_list)
3185 {
3186         memset (ctx, 0, sizeof (VerifyContext));
3187         ctx->image = image;
3188         ctx->report_error = error_list != NULL;
3189         ctx->valid = 1;
3190         ctx->size = image->raw_data_len;
3191         ctx->data = image->raw_data;
3192 }
3193
3194 static gboolean
3195 cleanup_context (VerifyContext *ctx, GSList **error_list)
3196 {
3197         g_free (ctx->sections);
3198         if (error_list)
3199                 *error_list = ctx->errors;
3200         else
3201                 mono_free_verify_list (ctx->errors);
3202         return ctx->valid;      
3203 }
3204
3205 gboolean
3206 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3207 {
3208         VerifyContext ctx;
3209
3210         if (!mono_verifier_is_enabled_for_image (image))
3211                 return TRUE;
3212
3213         init_verify_context (&ctx, image, error_list);
3214         ctx.stage = STAGE_PE;
3215
3216         verify_msdos_header (&ctx);
3217         CHECK_STATE();
3218         verify_pe_header (&ctx);
3219         CHECK_STATE();
3220         verify_pe_optional_header (&ctx);
3221         CHECK_STATE();
3222         load_section_table (&ctx);
3223         CHECK_STATE();
3224         load_data_directories (&ctx);
3225         CHECK_STATE();
3226         verify_import_table (&ctx);
3227         CHECK_STATE();
3228         /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
3229         verify_resources_table (&ctx);
3230
3231 cleanup:
3232         return cleanup_context (&ctx, error_list);
3233 }
3234
3235 gboolean
3236 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3237 {
3238         VerifyContext ctx;
3239
3240         if (!mono_verifier_is_enabled_for_image (image))
3241                 return TRUE;
3242
3243         init_verify_context (&ctx, image, error_list);
3244         ctx.stage = STAGE_CLI;
3245
3246         verify_cli_header (&ctx);
3247         CHECK_STATE();
3248         verify_metadata_header (&ctx);
3249         CHECK_STATE();
3250         verify_tables_schema (&ctx);
3251
3252 cleanup:
3253         return cleanup_context (&ctx, error_list);
3254 }
3255
3256
3257 /*
3258  * Verifies basic table constraints such as global table invariants (sorting, field monotonicity, etc).
3259  * Other verification checks are meant to be done lazily by the runtime. Those include:
3260  *      blob items (signatures, method headers, custom attributes, etc)
3261  *  type semantics related
3262  *  vtable related
3263  *  stuff that should not block other pieces from running such as bad types/methods/fields/etc.
3264  * 
3265  * The whole idea is that if this succeed the runtime is free to play around safely but any complex
3266  * operation still need more checking.
3267  */
3268 gboolean
3269 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3270 {
3271         VerifyContext ctx;
3272
3273         if (!mono_verifier_is_enabled_for_image (image))
3274                 return TRUE;
3275
3276         init_verify_context (&ctx, image, error_list);
3277         ctx.stage = STAGE_TABLES;
3278
3279         verify_tables_data (&ctx);
3280
3281         return cleanup_context (&ctx, error_list);
3282 }
3283
3284
3285 /*
3286  * Verifies all other constraints.
3287  */
3288 gboolean
3289 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3290 {
3291         VerifyContext ctx;
3292
3293         if (!mono_verifier_is_enabled_for_image (image))
3294                 return TRUE;
3295
3296         init_verify_context (&ctx, image, error_list);
3297         ctx.stage = STAGE_TABLES;
3298
3299         verify_typedef_table_full (&ctx);
3300         CHECK_STATE ();
3301         verify_field_table_full (&ctx);
3302         CHECK_STATE ();
3303         verify_method_table_full (&ctx);
3304         CHECK_STATE ();
3305         verify_memberref_table_full (&ctx);
3306         CHECK_STATE ();
3307         verify_cattr_table_full (&ctx);
3308         CHECK_STATE ();
3309         verify_field_marshal_table_full (&ctx);
3310         CHECK_STATE ();
3311         verify_decl_security_table_full (&ctx);
3312         CHECK_STATE ();
3313         verify_standalonesig_table_full (&ctx);
3314
3315 cleanup:
3316         return cleanup_context (&ctx, error_list);
3317 }
3318
3319 #else
3320 gboolean
3321 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
3322 {
3323         return TRUE;
3324 }
3325
3326 gboolean
3327 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3328 {
3329         return TRUE;
3330 }
3331
3332 gboolean
3333 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3334 {
3335         return TRUE;
3336 }
3337
3338 gboolean
3339 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
3340 {
3341         return TRUE;
3342 }
3343
3344 #endif /* DISABLE_VERIFIER */