2009-03-27 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / metadata / metadata-verify.c
1 /*
2  * metadata-verify.c: Metadata verfication support
3  *
4  * Author:
5  *      Mono Project (http://www.mono-project.com)
6  *
7  * Copyright (C) 2005-2008 Novell, Inc. (http://www.novell.com)
8  */
9
10 #include <mono/metadata/object-internals.h>
11 #include <mono/metadata/verify.h>
12 #include <mono/metadata/verify-internals.h>
13 #include <mono/metadata/opcodes.h>
14 #include <mono/metadata/tabledefs.h>
15 #include <mono/metadata/reflection.h>
16 #include <mono/metadata/debug-helpers.h>
17 #include <mono/metadata/mono-endian.h>
18 #include <mono/metadata/metadata.h>
19 #include <mono/metadata/metadata-internals.h>
20 #include <mono/metadata/class-internals.h>
21 #include <mono/metadata/tokentype.h>
22 #include <string.h>
23 #include <signal.h>
24 #include <ctype.h>
25
26 /*
27  TODO add fail fast mode
28  TODO add PE32+ support
29  TODO verify the entry point RVA and content.
30  TODO load_section_table and load_data_directories must take PE32+ into account
31  TODO add section relocation support
32  TODO verify the relocation table, since we really don't use, no need so far.
33  TODO do full PECOFF resources verification 
34  TODO verify in the CLI header entry point and resources 
35  FIXME has_cattr coded index / 8 -> Permission table? -- it's decl security
36  FIXME use subtraction based bounds checking to avoid overflows
37 */
38
39 #define INVALID_OFFSET ((guint32)-1)
40
41 enum {
42         IMPORT_TABLE_IDX = 1, 
43         RESOURCE_TABLE_IDX = 2,
44         RELOCATION_TABLE_IDX = 5,
45         IAT_IDX = 12,
46         CLI_HEADER_IDX = 14,
47 };
48
49 enum {
50         STRINGS_STREAM,
51         USER_STRINGS_STREAM,
52         BLOB_STREAM,
53         GUID_STREAM,
54         TILDE_STREAM
55 };
56
57 enum {
58         COL_UINT8,
59         COL_UINT16,
60         COL_UINT32,
61
62         COL_STRING,
63         COL_GUID,
64         COL_BLOB,
65
66         COL_TYPE_DEF_OR_REF, /*includes typespec*/
67         COL_HAS_CONSTANT,
68         COL_HAS_CATTR,
69         COL_HAS_FIELD_MARSHAL,
70         COL_HAS_DECL_SECURITY,
71         COL_MEMBER_REF_PARENT,
72         COL_HAS_SEMANTICS,
73         COL_METHOD_DEF_OR_REF,
74         COL_MEMBER_FORWARDED,
75         COL_IMPLEMENTATION,
76         COL_CATTR_TYPE,
77         COL_RES_SCOPE,
78         COL_TYPE_OR_METHOD_DEF,
79
80         COL_TYPE_DEF,
81         COL_METHOD_DEF,
82         COL_FIELD,
83         COL_PARAM,
84         COL_PROPERTY,
85         COL_EVENT,
86         COL_GENERIC_PARAM,
87         COL_ASSEMBLY_REF,
88         COL_MODULE_REF,
89
90         COL_LAST
91 };
92
93 const static unsigned char table_desc [] = {
94         /* 0x00 Module */
95         COL_UINT16, /*Generation*/
96         COL_STRING, /*Name*/
97         COL_GUID, /*Mvid*/
98         COL_GUID, /*EncId*/
99         COL_GUID, /*EncBaseId*/
100         COL_LAST,
101
102         /* 0x01 TypeRef */
103         COL_RES_SCOPE, /*ResolutionScope*/
104         COL_STRING, /*TypeName*/
105         COL_STRING, /*TypeNameSpace*/
106         COL_LAST,
107
108         /* 0x02 TypeDef */
109         COL_UINT32, /*Flags*/
110         COL_STRING, /*TypeName*/
111         COL_STRING, /*TypeNameSpace*/
112         COL_TYPE_DEF_OR_REF, /*Extends*/
113         COL_FIELD, /*FieldList*/
114         COL_METHOD_DEF, /*FieldList*/
115         COL_LAST,
116
117         /* 0x03 non documented extension */
118         COL_LAST,
119
120         /* 0x04 Field */
121         COL_UINT16, /*FieldAttributes*/
122         COL_STRING, /*Name*/
123         COL_BLOB, /*Signature*/
124         COL_LAST,
125
126         /* 0x05 non documented extension */
127         COL_LAST,
128
129         /* 0x06 MethodDef */
130         COL_UINT32, /*RVA*/
131         COL_UINT16, /*ImplFlags*/
132         COL_UINT16, /*Flags*/
133         COL_STRING, /*Name*/
134         COL_BLOB, /*Signature*/
135         COL_PARAM, /*ParamList*/
136         COL_LAST,
137
138         /* 0x07 non documented extension */
139         COL_LAST,
140
141         /* 0x08 Param */
142         COL_UINT16, /*Flags*/
143         COL_UINT16, /*Sequence*/
144         COL_STRING, /*Name*/
145         COL_LAST,
146
147         /* 0x09 InterfaceImpl */
148         COL_TYPE_DEF, /*Class*/
149         COL_TYPE_DEF_OR_REF, /*Interface*/
150         COL_LAST,
151         
152         /* 0x0A MemberRef */
153         COL_MEMBER_REF_PARENT, /*Class*/
154         COL_STRING, /*Name*/
155         COL_BLOB, /*Signature*/
156         COL_LAST,
157
158         /* 0x0B Constant */
159         COL_HAS_CONSTANT, /*Parent*/
160         COL_BLOB, /*Value*/
161         COL_LAST,
162
163         /* 0x0C CustomAttribute */
164         COL_HAS_CATTR, /*Parent*/
165         COL_CATTR_TYPE, /*Type*/
166         COL_BLOB, /*Value*/
167         COL_LAST,
168
169         /* 0x0D FieldMarshal */
170         COL_HAS_FIELD_MARSHAL, /*Parent*/
171         COL_BLOB, /*NativeType*/
172         COL_LAST,
173
174         /* 0x0E DeclSecurity */
175         COL_UINT16, /*Action*/
176         COL_HAS_DECL_SECURITY, /*Parent*/ 
177         COL_BLOB, /*PermissionSet*/
178         COL_LAST,
179
180         /* 0x0F ClassLayout */
181         COL_UINT16, /*Packingsize*/
182         COL_UINT32, /*ClassSize*/
183         COL_TYPE_DEF, /*Parent*/
184         COL_LAST,
185
186         /* 0x10 FieldLayout */
187         COL_UINT32, /*Offset*/
188         COL_FIELD, /*Field*/
189         COL_LAST,
190
191         /* 0x11 StandAloneSig */
192         COL_BLOB, /*Signature*/
193         COL_LAST,
194
195         /* 0x12 EventMap */
196         COL_TYPE_DEF, /*Parent*/
197         COL_EVENT, /*EventList*/
198         COL_LAST,
199
200         /* 0x13 non documented extension */
201         COL_LAST,
202
203         /* 0x14 Event */
204         COL_UINT16, /*EventFlags*/
205         COL_STRING, /*Name*/
206         COL_TYPE_DEF_OR_REF, /*EventType*/
207         COL_LAST,
208
209         /* 0x15 PropertyMap */
210         COL_TYPE_DEF, /*Parent*/
211         COL_PROPERTY, /*PropertyList*/
212         COL_LAST,
213
214         /* 0x16 non documented extension */
215         COL_LAST,
216
217         /* 0x17 Property */
218         COL_UINT16, /*Flags*/
219         COL_STRING, /*Name*/
220         COL_BLOB, /*Signature*/
221         COL_LAST,
222
223         /* 0x18 MethodSemantics */
224         COL_UINT16, /*Semantics*/
225         COL_METHOD_DEF, /*Method*/
226         COL_HAS_SEMANTICS, /*Association*/
227         COL_LAST,
228
229         /* 0x19 MethodImpl */
230         COL_TYPE_DEF, /*Class*/
231         COL_METHOD_DEF_OR_REF, /*MethodBody*/
232         COL_METHOD_DEF_OR_REF, /*MethodDeclaration*/
233         COL_LAST,
234
235         /* 0x1A ModuleRef */
236         COL_STRING, /*Name*/
237         COL_LAST,
238
239         /* 0x1B TypeSpec */
240         COL_BLOB, /*Signature*/
241         COL_LAST,
242
243         /* 0x1C ImplMap */
244         COL_UINT16, /*MappingFlags*/
245         COL_MEMBER_FORWARDED, /*MappingFlags*/
246         COL_STRING, /*ImportName*/
247         COL_MODULE_REF, /*ImportScope*/
248         COL_LAST,
249
250         /* 0x1D FieldRVA */
251         COL_UINT32, /*RVA*/
252         COL_FIELD, /*Field*/
253         COL_LAST,
254
255         /* 0x1E Unused */
256         COL_LAST,
257
258         /* 0x1F Unused */
259         COL_LAST,
260
261         /* 0x20 Assembly */
262         COL_UINT32, /*HashAlgId*/
263         COL_UINT16, /*Major*/
264         COL_UINT16, /*Minor*/
265         COL_UINT16, /*Build*/
266         COL_UINT16, /*Revision*/
267         COL_UINT32, /*Flags*/
268         COL_BLOB, /*PublicKey*/
269         COL_STRING, /*Name*/
270         COL_STRING, /*Culture*/
271         COL_LAST,
272
273         /* 0x21 AssemblyProcessor */
274         COL_UINT32, /*Processor*/
275         COL_LAST,
276
277         /* 0x22 AssemblyOS */
278         COL_UINT32, /*OSPlatformID*/
279         COL_UINT32, /*OSMajorVersion*/
280         COL_UINT32, /*OSMinorVersion*/
281         COL_LAST,
282
283         /* 0x23 AssemblyRef */
284         COL_UINT16, /*Major*/
285         COL_UINT16, /*Minor*/
286         COL_UINT16, /*Build*/
287         COL_UINT16, /*Revision*/
288         COL_UINT32, /*Flags*/
289         COL_BLOB, /*PublicKeyOrToken*/
290         COL_STRING, /*Name*/
291         COL_STRING, /*Culture*/
292         COL_BLOB, /*HashValue*/
293         COL_LAST,
294
295         /* 0x24 AssemblyRefProcessor */
296         COL_UINT32, /*Processor*/
297         COL_ASSEMBLY_REF, /*AssemblyRef*/
298         COL_LAST,
299
300         /* 0x25 AssemblyRefOS */
301         COL_UINT32, /*OSPlatformID*/
302         COL_UINT32, /*OSMajorVersion*/
303         COL_UINT32, /*OSMinorVersion*/
304         COL_ASSEMBLY_REF, /*AssemblyRef*/
305         COL_LAST,
306
307         /* 0x26 Unused */
308         COL_UINT32, /*Flags*/
309         COL_STRING, /*Name*/
310         COL_BLOB, /*HashValue*/
311         COL_LAST,
312
313         /* 0x27 ExportedType */
314         COL_UINT32, /*Flags*/
315         COL_UINT32, /*TypeDefId*/
316         COL_STRING, /*TypeName*/
317         COL_STRING, /*TypeNamespace*/
318         COL_IMPLEMENTATION, /*Implementation*/
319         COL_LAST,
320
321         /* 0x28 ManifestResource  */
322         COL_UINT32, /*Offset*/
323         COL_UINT32, /*Flags*/
324         COL_STRING, /*Name*/
325         COL_IMPLEMENTATION, /*Implementation*/
326         COL_LAST,
327
328         /* 0x29 NestedClass  */
329         COL_TYPE_DEF, /*NestedClass*/
330         COL_TYPE_DEF, /*EnclosingClass*/
331         COL_LAST,
332
333         /* 0x2A GenericParam  */
334         COL_UINT16, /*Number*/
335         COL_UINT16, /*Flags*/
336         COL_TYPE_OR_METHOD_DEF, /*Owner*/
337         COL_STRING, /*Name*/
338         COL_LAST,
339
340         /* 0x2B MethodSpec  */
341         COL_METHOD_DEF_OR_REF, /*Method*/
342         COL_BLOB, /*Instantiation*/
343         COL_LAST,
344
345         /* 0x2C GenericParamConstraint  */
346         COL_GENERIC_PARAM, /*Owner*/
347         COL_TYPE_DEF_OR_REF, /*Constraint*/
348         COL_LAST,
349 };
350
351
352 typedef struct {
353         guint32 rva;
354         guint32 size;
355         guint32 translated_offset;
356 } DataDirectory;
357
358 typedef struct {
359         guint32 offset;
360         guint32 size;
361 } OffsetAndSize;
362
363 typedef struct {
364         guint32 baseRVA;
365         guint32 baseOffset;
366         guint32 size;
367         guint32 rellocationsRVA;
368         guint16 numberOfRelocations;
369 } SectionHeader;
370
371 typedef struct {
372         guint32 row_count;
373         guint32 row_size;
374 } TableInfo;
375
376 typedef struct {
377         const char *data;
378         guint32 size;
379         GSList *errors;
380         int valid;
381         guint32 section_count, tables_offset;
382         SectionHeader *sections;
383         gboolean wide_strings, wide_guid, wide_blob;
384
385         DataDirectory data_directories [16];
386         OffsetAndSize metadata_streams [5]; //offset from begin of the image
387         TableInfo tables [MONO_TABLE_NUM];
388         guint32 field_sizes [COL_LAST];
389 } VerifyContext;
390
391 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception)    \
392         do {    \
393                 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1);      \
394                 vinfo->info.status = __status;  \
395                 vinfo->info.message = ( __msg); \
396                 vinfo->exception_type = (__exception);  \
397                 (__ctx)->errors = g_slist_prepend ((__ctx)->errors, vinfo);     \
398         } while (0)
399
400
401 #define ADD_ERROR(__ctx, __msg) \
402         do {    \
403                 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
404                 (__ctx)->valid = 0; \
405                 return; \
406         } while (0)
407
408 #define CHECK_STATE() do { if (!ctx.valid) goto cleanup; } while (0)
409
410 #define CHECK_ERROR() do { if (!ctx->valid) return; } while (0)
411
412 static guint32
413 pe_signature_offset (VerifyContext *ctx)
414 {
415         return read32 (ctx->data + 0x3c);
416 }
417
418 static guint32
419 pe_header_offset (VerifyContext *ctx)
420 {
421         return read32 (ctx->data + 0x3c) + 4;
422 }
423
424 static gboolean
425 bounds_check_virtual_address (VerifyContext *ctx, guint32 rva, guint32 size)
426 {
427         int i;
428
429         if (!ctx->sections)
430                 return FALSE;
431
432         for (i = 0; i < ctx->section_count; ++i) {
433                 guint32 base = ctx->sections [i].baseRVA;
434                 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
435                 if (rva >= base && rva + size <= end)
436                         return TRUE;
437         }
438         return FALSE;
439 }
440
441 static gboolean
442 bounds_check_datadir (DataDirectory *dir, guint32 offset, guint32 size)
443 {
444         if (dir->translated_offset > offset)
445                 return FALSE;
446         if (dir->size < size)
447                 return FALSE;
448         return offset + size <= dir->translated_offset + dir->size;
449 }
450
451 static gboolean
452 bounds_check_offset (OffsetAndSize *off, guint32 offset, guint32 size)
453 {
454         if (off->offset > offset)
455                 return FALSE;
456         
457         if (off->size < size)
458                 return FALSE;
459
460         return offset + size <= off->offset + off->size;
461 }
462
463 static guint32
464 translate_rva (VerifyContext *ctx, guint32 rva)
465 {
466         int i;
467
468         if (!ctx->sections)
469                 return FALSE;
470
471         for (i = 0; i < ctx->section_count; ++i) {
472                 guint32 base = ctx->sections [i].baseRVA;
473                 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
474                 if (rva >= base && rva <= end) {
475                         guint32 res = (rva - base) + ctx->sections [i].baseOffset;
476                         /* double check */
477                         return res >= ctx->size ? INVALID_OFFSET : res;
478                 }
479         }
480
481         return INVALID_OFFSET;
482 }
483
484 static void
485 verify_msdos_header (VerifyContext *ctx)
486 {
487         guint32 lfanew;
488         if (ctx->size < 128)
489                 ADD_ERROR (ctx, g_strdup ("Not enough space for the MS-DOS header"));
490         if (ctx->data [0] != 0x4d || ctx->data [1] != 0x5a)
491                 ADD_ERROR (ctx,  g_strdup ("Invalid MS-DOS watermark"));
492         lfanew = pe_signature_offset (ctx);
493         if (lfanew > ctx->size - 4)
494                 ADD_ERROR (ctx, g_strdup ("MS-DOS lfanew offset points to outside of the file"));
495 }
496
497 static void
498 verify_pe_header (VerifyContext *ctx)
499 {
500         guint32 offset = pe_signature_offset (ctx);
501         const char *pe_header = ctx->data + offset;
502         if (pe_header [0] != 'P' || pe_header [1] != 'E' ||pe_header [2] != 0 ||pe_header [3] != 0)
503                 ADD_ERROR (ctx,  g_strdup ("Invalid PE header watermark"));
504         pe_header += 4;
505         offset += 4;
506
507         if (offset > ctx->size - 20)
508                 ADD_ERROR (ctx, g_strdup ("File with truncated pe header"));
509         if (read16 (pe_header) != 0x14c)
510                 ADD_ERROR (ctx, g_strdup ("Invalid PE header Machine value"));
511 }
512
513 static void
514 verify_pe_optional_header (VerifyContext *ctx)
515 {
516         guint32 offset = pe_header_offset (ctx);
517         guint32 header_size, file_alignment;
518         const char *pe_header = ctx->data + offset;
519         const char *pe_optional_header = pe_header + 20;
520
521         header_size = read16 (pe_header + 16);
522         offset += 20;
523
524         if (header_size < 2) /*must be at least 2 or we won't be able to read magic*/
525                 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
526
527         if (offset > ctx->size - header_size || header_size > ctx->size)
528                 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
529
530         if (read16 (pe_optional_header) == 0x10b) {
531                 if (header_size != 224)
532                         ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header size %d", header_size));
533
534                 /*if (read32 (pe_optional_header + 28) != 0x400000)
535                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Image base %x", read32 (pe_optional_header + 28)));*/
536                 if (read32 (pe_optional_header + 32) != 0x2000)
537                         ADD_ERROR (ctx, g_strdup_printf ("Invalid Section Aligmnent %x", read32 (pe_optional_header + 32)));
538                 file_alignment = read32 (pe_optional_header + 36);
539                 if (file_alignment != 0x200 && file_alignment != 0x1000)
540                         ADD_ERROR (ctx, g_strdup_printf ("Invalid file Aligmnent %x", file_alignment));
541                 /* All the junk in the middle is irrelevant, specially for mono. */
542                 if (read32 (pe_optional_header + 92) > 0x10)
543                         ADD_ERROR (ctx, g_strdup_printf ("Too many data directories %x", read32 (pe_optional_header + 92)));
544         } else {
545                 if (read16 (pe_optional_header) == 0x20B)
546                         ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle PE32+"));
547                 else
548                         ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header magic %d", read16 (pe_optional_header)));
549         }
550 }
551
552 static void
553 load_section_table (VerifyContext *ctx)
554 {
555         int i;
556         SectionHeader *sections;
557         guint32 offset =  pe_header_offset (ctx);
558         const char *ptr = ctx->data + offset;
559         guint16 num_sections = ctx->section_count = read16 (ptr + 2);
560
561         offset += 244;/*FIXME, this constant is different under PE32+*/
562         ptr += 244;
563
564         if (num_sections * 40 > ctx->size - offset)
565                 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
566
567         sections = ctx->sections = g_new0 (SectionHeader, num_sections);
568         for (i = 0; i < num_sections; ++i) {
569                 sections [i].size = read32 (ptr + 8);
570                 sections [i].baseRVA = read32 (ptr + 12);
571                 sections [i].baseOffset = read32 (ptr + 20);
572                 sections [i].rellocationsRVA = read32 (ptr + 24);
573                 sections [i].numberOfRelocations = read16 (ptr + 32);
574                 ptr += 40;
575         }
576
577         ptr = ctx->data + offset; /*reset it to the beggining*/
578         for (i = 0; i < num_sections; ++i) {
579                 guint32 raw_size, flags;
580                 if (sections [i].baseOffset == 0)
581                         ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with intialized data only"));
582                 if (sections [i].baseOffset >= ctx->size)
583                         ADD_ERROR (ctx, g_strdup_printf ("Invalid PointerToRawData %x points beyond EOF", sections [i].baseOffset));
584                 if (sections [i].size > ctx->size - sections [i].baseOffset)
585                         ADD_ERROR (ctx, g_strdup ("Invalid VirtualSize points beyond EOF"));
586
587                 raw_size = read32 (ptr + 16);
588                 if (raw_size < sections [i].size)
589                         ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with SizeOfRawData < VirtualSize"));
590
591                 if (raw_size > ctx->size - sections [i].baseOffset)
592                         ADD_ERROR (ctx, g_strdup_printf ("Invalid SizeOfRawData %x points beyond EOF", raw_size));
593
594                 if (sections [i].rellocationsRVA || sections [i].numberOfRelocations)
595                         ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't handle section relocation"));
596
597                 flags = read32 (ptr + 36);
598                 /*TODO 0xFE0000E0 is all flags from cil-coff.h OR'd. Make it a less magical number*/
599                 if (flags == 0 || (flags & ~0xFE0000E0) != 0)
600                         ADD_ERROR (ctx, g_strdup_printf ("Invalid section flags %x", flags));
601
602                 ptr += 40;
603         }
604 }
605
606 static gboolean
607 is_valid_data_directory (int i)
608 {
609         /*LAMESPEC 4 == certificate 6 == debug, MS uses both*/
610         return i == 1 || i == 2 || i == 5 || i == 12 || i == 14 || i == 4 || i == 6; 
611 }
612
613 static void
614 load_data_directories (VerifyContext *ctx)
615 {
616         guint32 offset =  pe_header_offset (ctx) + 116; /*FIXME, this constant is different under PE32+*/
617         const char *ptr = ctx->data + offset;
618         int i;
619
620         for (i = 0; i < 16; ++i) {
621                 guint32 rva = read32 (ptr);
622                 guint32 size = read32 (ptr + 4);
623
624                 if ((rva != 0 || size != 0) && !is_valid_data_directory (i))
625                         ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d", i));
626
627                 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
628                         ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d rva/size pair %x/%x", i, rva, size));
629
630                 ctx->data_directories [i].rva = rva;
631                 ctx->data_directories [i].size = size;
632                 ctx->data_directories [i].translated_offset = translate_rva (ctx, rva);
633
634                 ptr += 8;
635         }
636 }
637
638 #define SIZE_OF_MSCOREE (sizeof ("mscoree.dll"))
639
640 #define SIZE_OF_CORMAIN (sizeof ("_CorExeMain"))
641
642 static void
643 verify_hint_name_table (VerifyContext *ctx, guint32 import_rva, const char *table_name)
644 {
645         const char *ptr;
646         guint32 hint_table_rva;
647
648         import_rva = translate_rva (ctx, import_rva);
649         g_assert (import_rva != INVALID_OFFSET);
650
651         hint_table_rva = read32 (ctx->data + import_rva);
652         if (!bounds_check_virtual_address (ctx, hint_table_rva, SIZE_OF_CORMAIN + 2))
653                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint/Name rva %d for %s", hint_table_rva, table_name));
654
655         hint_table_rva = translate_rva (ctx, hint_table_rva);
656         g_assert (hint_table_rva != INVALID_OFFSET);
657         ptr = ctx->data + hint_table_rva + 2;
658
659         if (memcmp ("_CorExeMain", ptr, SIZE_OF_CORMAIN) && memcmp ("_CorDllMain", ptr, SIZE_OF_CORMAIN)) {
660                 char name[SIZE_OF_CORMAIN];
661                 memcpy (name, ptr, SIZE_OF_CORMAIN);
662                 name [SIZE_OF_CORMAIN - 1] = 0;
663                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint / Name: '%s'", name));
664         }
665 }
666
667 static void
668 verify_import_table (VerifyContext *ctx)
669 {
670         DataDirectory it = ctx->data_directories [IMPORT_TABLE_IDX];
671         guint32 offset = it.translated_offset;
672         const char *ptr = ctx->data + offset;
673         guint32 name_rva, ilt_rva, iat_rva;
674
675         g_assert (offset != INVALID_OFFSET);
676
677         if (it.size < 40)
678                 ADD_ERROR (ctx, g_strdup_printf ("Import table size %d is smaller than 40", it.size));
679
680         ilt_rva = read32 (ptr);
681         if (!bounds_check_virtual_address (ctx, ilt_rva, 8))
682                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Lookup Table rva %x", ilt_rva));
683
684         name_rva = read32 (ptr + 12);
685         if (!bounds_check_virtual_address (ctx, name_rva, SIZE_OF_MSCOREE))
686                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name rva %x", name_rva));
687
688         iat_rva = read32 (ptr + 16);
689         if (!bounds_check_virtual_address (ctx, iat_rva, 8))
690                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Address Table rva %x", iat_rva));
691
692         if (iat_rva != ctx->data_directories [IAT_IDX].rva)
693                 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));
694
695         name_rva = translate_rva (ctx, name_rva);
696         g_assert (name_rva != INVALID_OFFSET);
697         ptr = ctx->data + name_rva;
698
699         if (memcmp ("mscoree.dll", ptr, SIZE_OF_MSCOREE)) {
700                 char name[SIZE_OF_MSCOREE];
701                 memcpy (name, ptr, SIZE_OF_MSCOREE);
702                 name [SIZE_OF_MSCOREE - 1] = 0;
703                 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name: '%s'", name));
704         }
705         
706         verify_hint_name_table (ctx, ilt_rva, "Import Lookup Table");
707         CHECK_ERROR ();
708         verify_hint_name_table (ctx, iat_rva, "Import Address Table");
709 }
710
711 static void
712 verify_resources_table (VerifyContext *ctx)
713 {
714         DataDirectory it = ctx->data_directories [RESOURCE_TABLE_IDX];
715         guint32 offset;
716         guint16 named_entries, id_entries;
717         const char *ptr, *root, *end;
718
719         if (it.rva == 0)
720                 return;
721
722         if (it.size < 16)
723                 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));
724
725         offset = it.translated_offset;
726         root = ptr = ctx->data + offset;
727         end = root + it.size;
728
729         g_assert (offset != INVALID_OFFSET);
730
731         named_entries = read16 (ptr + 12);
732         id_entries = read16 (ptr + 14);
733
734         printf ("named %d id_entries %d\n", named_entries, id_entries);
735         if ((named_entries + id_entries) * 8 + 16 > it.size)
736                 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));
737
738         if (named_entries || id_entries)
739                 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support full verification of PECOFF resources"));
740 }
741
742 static void
743 verify_cli_header (VerifyContext *ctx)
744 {
745         DataDirectory it = ctx->data_directories [CLI_HEADER_IDX];
746         guint32 offset;
747         const char *ptr;
748         int i;
749
750         if (it.rva == 0)
751                 ADD_ERROR (ctx, g_strdup_printf ("CLI header missing"));
752
753         if (it.size != 72)
754                 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size in data directory %d must be 72", it.size));
755
756         offset = it.translated_offset;
757         ptr = ctx->data + offset;
758
759         g_assert (offset != INVALID_OFFSET);
760
761         if (read16 (ptr) != 72)
762                 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size %d must be 72", read16 (ptr)));
763
764         if (!bounds_check_virtual_address (ctx, read32 (ptr + 8), read32 (ptr + 12)))
765                 ADD_ERROR (ctx, g_strdup_printf ("Invalid medatata section rva/size pair %x/%x", read32 (ptr + 8), read32 (ptr + 12)));
766
767         if (!read32 (ptr + 8) || !read32 (ptr + 12))
768                 ADD_ERROR (ctx, g_strdup_printf ("Missing medatata section in the CLI header"));
769
770         if ((read32 (ptr + 16) & ~0x0001000B) != 0)
771                 ADD_ERROR (ctx, g_strdup_printf ("Invalid CLI header flags"));
772
773         ptr += 24;
774         for (i = 0; i < 6; ++i) {
775                 guint32 rva = read32 (ptr);
776                 guint32 size = read32 (ptr + 4);
777
778                 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
779                         ADD_ERROR (ctx, g_strdup_printf ("Invalid cli section %i rva/size pair %x/%x", i, rva, size));
780
781                 ptr += 8;
782
783                 if (rva && i > 1)
784                         ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't support cli header section %d", i));
785         }
786 }
787
788 static guint32
789 pad4 (guint32 offset)
790 {
791         if (offset & 0x3) //pad to the next 4 byte boundary
792                 offset = (offset & ~0x3) + 4;
793         return offset;
794 }
795
796 static void
797 verify_metadata_header (VerifyContext *ctx)
798 {
799         int i;
800         DataDirectory it = ctx->data_directories [CLI_HEADER_IDX];
801         guint32 offset;
802         const char *ptr;
803
804         offset = it.translated_offset;
805         ptr = ctx->data + offset;
806         g_assert (offset != INVALID_OFFSET);
807
808         //build a directory entry for the metadata root
809         ptr += 8;
810         it.rva = read32 (ptr);
811         ptr += 4;
812         it.size = read32 (ptr);
813         it.translated_offset = offset = translate_rva (ctx, it.rva);
814
815         ptr = ctx->data + offset;
816         g_assert (offset != INVALID_OFFSET);
817
818         if (it.size < 20)
819                 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small %d (at least 20 bytes required for initial decoding)", it.size));
820
821         if (read32 (ptr) != 0x424A5342)
822                 ADD_ERROR (ctx, g_strdup_printf ("Invalid metadata signature, expected 0x424A5342 but got %08x", read32 (ptr)));
823
824         offset = pad4 (offset + 16 + read32 (ptr + 12));
825
826         if (!bounds_check_datadir (&it, offset, 4))
827                 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));
828
829         ptr = ctx->data + offset; //move to streams header 
830
831         if (read16 (ptr + 2) != 5)
832                 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section have %d streams (it must have exactly 5)", read16 (ptr + 2)));
833
834         ptr += 4;
835         offset += 4;
836
837         for (i = 0; i < 5; ++i) {
838                 guint32 stream_off, stream_size;
839                 int string_size, stream_idx;
840
841                 if (!bounds_check_datadir (&it, offset, 8))
842                         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));
843
844                 stream_off = it.translated_offset + read32 (ptr);
845                 stream_size = read32 (ptr + 4);
846
847                 if (!bounds_check_datadir (&it,  stream_off, stream_size))
848                         ADD_ERROR (ctx, g_strdup_printf ("Invalid stream header %d offset/size pair %x/%x", 0, stream_off, stream_size));
849
850                 ptr += 8;
851                 offset += 8;
852
853                 for (string_size = 0; string_size < 32; ++string_size) {
854                         if (!bounds_check_datadir (&it, offset++, 1))
855                                 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small to decode stream header %d name", i));
856                         if (!ptr [string_size])
857                                 break;
858                 }
859
860                 if (ptr [string_size])
861                         ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d name larger than 32 bytes", i));
862
863                 if (!strncmp ("#Strings", ptr, 9))
864                         stream_idx = STRINGS_STREAM;
865                 else if (!strncmp ("#US", ptr, 4))
866                         stream_idx = USER_STRINGS_STREAM;
867                 else if (!strncmp ("#Blob", ptr, 6))
868                         stream_idx = BLOB_STREAM;
869                 else if (!strncmp ("#GUID", ptr, 6))
870                         stream_idx = GUID_STREAM;
871                 else if (!strncmp ("#~", ptr, 3))
872                         stream_idx = TILDE_STREAM;
873                 else
874                         ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d invalid name %s", i, ptr));
875
876                 if (ctx->metadata_streams [stream_idx].offset != 0)
877                         ADD_ERROR (ctx, g_strdup_printf ("Duplicated metadata stream header %s", ptr));
878
879                 ctx->metadata_streams [stream_idx].offset = stream_off;
880                 ctx->metadata_streams [stream_idx].size = stream_size;
881
882                 offset = pad4 (offset);
883                 ptr = ctx->data + offset;
884         }
885 }
886
887 static void
888 verify_tables_schema (VerifyContext *ctx)
889 {
890         OffsetAndSize tables_area = ctx->metadata_streams [TILDE_STREAM];
891         unsigned offset = tables_area.offset;
892         const char *ptr = ctx->data + offset;
893         guint64 valid_tables;
894         guint32 count;
895         int i;
896
897         if (tables_area.size < 24)
898                 ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for initial decoding (requires 24 bytes)", tables_area.size));
899
900         if (ptr [4] != 2)
901                 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata major version %d, expected 2", ptr [4]));
902         if (ptr [5] != 0)
903                 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata minor version %d, expected 0", ptr [5]));
904
905         if ((ptr [6] & ~0x7) != 0)
906                 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]));
907
908         ctx->wide_strings = ptr [6] & 0x1;
909         ctx->wide_guid = ptr [6] & 0x2;
910         ctx->wide_blob = ptr [6] & 04;
911
912         valid_tables = read64 (ptr + 8);
913         count = 0;
914         for (i = 0; i < 64; ++i) {
915                 if (!(valid_tables & ((guint64)1 << i)))
916                         continue;
917
918                 /*MS Extensions: 0x3 0x5 0x7 0x13 0x16
919                   Unused: 0x1E 0x1F 0x2D-0x3F
920                   We don't care about the MS extensions.*/
921                 if (i == 0x3 || i == 0x5 || i == 0x7 || i == 0x13 || i == 0x16)
922                         ADD_ERROR (ctx, g_strdup_printf ("The metadata verifies doesn't support MS specific table %x", i));
923                 if (i == 0x1E || i == 0x1F || i >= 0x2D)
924                         ADD_ERROR (ctx, g_strdup_printf ("Invalid table %x", i));
925                 ++count;
926         }
927
928         if (tables_area.size < 24 + count * 4)
929                 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));
930
931         ptr += 24;
932
933         for (i = 0; i < 64; ++i) {
934                 if (valid_tables & ((guint64)1 << i)) {
935                         ctx->tables [i].row_count = read32 (ptr);
936                         ptr += 4;
937                 }
938         }
939         ctx->tables_offset = offset + 24 + count * 4;
940 }
941
942 static guint32
943 enc_index_size (guint32 bits, guint32 max)
944 {
945         guint32 size = 1 << (16 - bits); 
946         return max >= size ? 4 : 2;
947 }
948
949 static void
950 calc_fields_size (VerifyContext *ctx)
951 {
952 #define TS(T) (ctx->tables [T].row_count)
953 #define MAX2(TA,TB) MAX (TS (TA), TS (TB))
954 #define MAX3(TA,TB,TC) MAX (TS (TA), MAX (TS (TB), TS (TC)))
955 #define TB_SIZE(T) (TS (T) >= (1 << 16) ? 4 : 2)
956
957         int tmp;
958         memset (ctx->field_sizes, 0, sizeof (guint32) * COL_LAST);
959         
960         ctx->field_sizes [COL_UINT8] = 1;
961         ctx->field_sizes [COL_UINT16] = 2;
962         ctx->field_sizes [COL_UINT32] = 4;
963
964         ctx->field_sizes [COL_STRING] = ctx->wide_strings ? 4 : 2;
965         ctx->field_sizes [COL_GUID] = ctx->wide_guid ? 4 : 2;
966         ctx->field_sizes [COL_BLOB] = ctx->wide_blob? 4 : 2;
967
968         ctx->field_sizes [COL_TYPE_DEF_OR_REF] = enc_index_size (2, MAX3 (MONO_TABLE_TYPEDEF, MONO_TABLE_TYPEREF, MONO_TABLE_TYPESPEC));
969         ctx->field_sizes [COL_HAS_CONSTANT] = enc_index_size (2, MAX3 (MONO_TABLE_FIELD, MONO_TABLE_PARAM, MONO_TABLE_PROPERTY));
970
971         tmp = MAX3 (MONO_TABLE_METHOD, MONO_TABLE_FIELD, MONO_TABLE_TYPEREF);
972         tmp = MAX (tmp, MAX3 (MONO_TABLE_TYPEDEF, MONO_TABLE_PARAM, MONO_TABLE_INTERFACEIMPL));
973         tmp = MAX (tmp, MAX3 (MONO_TABLE_MEMBERREF, MONO_TABLE_MODULE, COL_HAS_DECL_SECURITY));
974         tmp = MAX (tmp, MAX3 (MONO_TABLE_PROPERTY, MONO_TABLE_EVENT, MONO_TABLE_STANDALONESIG));
975         tmp = MAX (tmp, MAX3 (MONO_TABLE_MODULEREF, MONO_TABLE_TYPESPEC, MONO_TABLE_ASSEMBLY));
976         tmp = MAX (tmp, MAX3 (MONO_TABLE_ASSEMBLYREF, MONO_TABLE_FILE, MONO_TABLE_EXPORTEDTYPE));
977         tmp = MAX (tmp, MONO_TABLE_MANIFESTRESOURCE);
978         ctx->field_sizes [COL_HAS_CATTR] = enc_index_size (5, tmp);
979
980         ctx->field_sizes [COL_HAS_FIELD_MARSHAL] = enc_index_size (1, MAX2 (MONO_TABLE_FIELD, MONO_TABLE_PARAM));
981         ctx->field_sizes [COL_HAS_DECL_SECURITY] = enc_index_size (2, MAX3 (MONO_TABLE_TYPEDEF, MONO_TABLE_METHOD, MONO_TABLE_ASSEMBLY));
982
983         tmp = MAX3 (MONO_TABLE_TYPEDEF, MONO_TABLE_TYPEREF, MONO_TABLE_MODULEREF);
984         tmp = MAX (tmp, MAX2 (MONO_TABLE_METHOD, MONO_TABLE_TYPESPEC));
985         ctx->field_sizes [COL_MEMBER_REF_PARENT] = enc_index_size (3, tmp);
986
987         ctx->field_sizes [COL_HAS_SEMANTICS] = enc_index_size (1, MAX2 (MONO_TABLE_EVENT, MONO_TABLE_PROPERTY));
988         ctx->field_sizes [COL_METHOD_DEF_OR_REF] = enc_index_size (1, MAX2 (MONO_TABLE_METHOD, MONO_TABLE_MEMBERREF));
989         ctx->field_sizes [COL_MEMBER_FORWARDED] = enc_index_size (1, MAX2 (MONO_TABLE_FIELD, MONO_TABLE_METHOD));
990         ctx->field_sizes [COL_IMPLEMENTATION] = enc_index_size (2, MAX3 (MONO_TABLE_FILE, MONO_TABLE_ASSEMBLYREF, MONO_TABLE_EXPORTEDTYPE));
991
992         ctx->field_sizes [COL_CATTR_TYPE] = enc_index_size (3, MAX2 (MONO_TABLE_METHOD, MONO_TABLE_MEMBERREF));
993         ctx->field_sizes [COL_RES_SCOPE] = enc_index_size (2, MAX (MAX2 (MONO_TABLE_MODULE, MONO_TABLE_MODULEREF), MAX2 (MONO_TABLE_ASSEMBLYREF, MONO_TABLE_TYPEREF))); 
994         ctx->field_sizes [COL_TYPE_OR_METHOD_DEF] = enc_index_size (1, MAX2 (MONO_TABLE_TYPEDEF, MONO_TABLE_METHOD));
995
996         ctx->field_sizes [COL_TYPE_DEF] = TB_SIZE (MONO_TABLE_TYPEDEF);
997         ctx->field_sizes [COL_METHOD_DEF] = TB_SIZE (MONO_TABLE_TYPEDEF);
998         ctx->field_sizes [COL_FIELD] = TB_SIZE (MONO_TABLE_TYPEDEF);
999         ctx->field_sizes [COL_PARAM] = TB_SIZE (MONO_TABLE_TYPEDEF);
1000         ctx->field_sizes [COL_PROPERTY] = TB_SIZE (MONO_TABLE_TYPEDEF);
1001         ctx->field_sizes [COL_EVENT] = TB_SIZE (MONO_TABLE_TYPEDEF);
1002         ctx->field_sizes [COL_GENERIC_PARAM] = TB_SIZE (MONO_TABLE_TYPEDEF);
1003         ctx->field_sizes [COL_ASSEMBLY_REF] = TB_SIZE (MONO_TABLE_TYPEDEF);
1004         ctx->field_sizes [COL_MODULE_REF] = TB_SIZE (MONO_TABLE_TYPEDEF);
1005 }
1006
1007 static guint32
1008 calc_row_size (VerifyContext *ctx)
1009 {
1010         int i, idx;
1011         guint64 total_size = 0;
1012         
1013         for (idx = 0, i = 0; i < 0x2D; ++i) {
1014                 int size = 0, type;
1015
1016                 while ((type = table_desc [idx++]) != COL_LAST)
1017                         size += ctx->field_sizes [type];
1018
1019                 ctx->tables [i].row_size = size;
1020                 total_size += (guint64)size * ctx->tables [i].row_count;
1021         }
1022
1023         if (total_size > G_MAXUINT32)
1024                 return 0;
1025
1026         return (guint32)total_size; 
1027 }
1028
1029
1030 static void
1031 verify_tables_data (VerifyContext *ctx)
1032 {
1033         OffsetAndSize tables_area = ctx->metadata_streams [TILDE_STREAM];
1034         guint table_area_size;
1035         calc_fields_size (ctx);
1036         table_area_size = calc_row_size (ctx);
1037
1038         if (table_area_size == 0)
1039                 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
1040
1041         if (!bounds_check_offset (&tables_area, ctx->tables_offset, table_area_size))
1042                 ADD_ERROR (ctx, g_strdup_printf ("Tables data require %d bytes but the only %d are available in the #~ stream", table_area_size, tables_area.size - (ctx->tables_offset - tables_area.offset)));
1043 }
1044
1045 GSList*
1046 mono_image_verify (const char *data, guint32 size)
1047 {
1048         VerifyContext ctx;
1049         memset (&ctx, 0, sizeof (VerifyContext));
1050         ctx.data = data;
1051         ctx.size = size;
1052         ctx.valid = 1;
1053
1054         verify_msdos_header (&ctx);
1055         CHECK_STATE();
1056         verify_pe_header (&ctx);
1057         CHECK_STATE();
1058         verify_pe_optional_header (&ctx);
1059         CHECK_STATE();
1060         load_section_table (&ctx);
1061         CHECK_STATE();
1062         load_data_directories (&ctx);
1063         CHECK_STATE();
1064         verify_import_table (&ctx);
1065         CHECK_STATE();
1066         /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
1067         verify_resources_table (&ctx);
1068         CHECK_STATE();
1069         verify_cli_header (&ctx);
1070         CHECK_STATE();
1071         verify_metadata_header (&ctx);
1072         CHECK_STATE();
1073         verify_tables_schema (&ctx);
1074         CHECK_STATE();
1075         verify_tables_data (&ctx);
1076         CHECK_STATE();
1077 cleanup:
1078         g_free (ctx.sections);
1079         return ctx.errors;
1080 }