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