1 /**
2 * \file
3 * Metadata verfication support
4 *
5 * Author:
6 * Mono Project (http://www.mono-project.com)
7 *
8 * Copyright (C) 2005-2008 Novell, Inc. (http://www.novell.com)
9 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
10 */
11 #include <config.h>
12 #include <mono/metadata/object-internals.h>
13 #include <mono/metadata/verify.h>
14 #include <mono/metadata/verify-internals.h>
15 #include <mono/metadata/opcodes.h>
16 #include <mono/metadata/tabledefs.h>
17 #include <mono/metadata/reflection.h>
18 #include <mono/metadata/reflection-internals.h>
19 #include <mono/metadata/debug-helpers.h>
20 #include <mono/metadata/mono-endian.h>
21 #include <mono/metadata/metadata.h>
22 #include <mono/metadata/metadata-internals.h>
23 #include <mono/metadata/class-internals.h>
24 #include <mono/metadata/tokentype.h>
25 #include <mono/metadata/security-manager.h>
26 #include <mono/metadata/security-core-clr.h>
27 #include <mono/metadata/cil-coff.h>
28 #include <mono/metadata/attrdefs.h>
29 #include <mono/utils/strenc.h>
30 #include <mono/utils/mono-error-internals.h>
31 #include <mono/utils/bsearch.h>
32 #include <string.h>
33 //#include <signal.h>
34 #include <ctype.h>
35
36 #ifndef DISABLE_VERIFIER
37 /*
38 TODO add fail fast mode
39 TODO add PE32+ support
40 TODO verify the entry point RVA and content.
41 TODO load_section_table and load_data_directories must take PE32+ into account
42 TODO add section relocation support
43 TODO verify the relocation table, since we really don't use, no need so far.
44 TODO do full PECOFF resources verification
45 TODO verify in the CLI header entry point and resources
46 TODO implement null token typeref validation
47 TODO verify table wide invariants for typedef (sorting and uniqueness)
48 TODO implement proper authenticode data directory validation
49 TODO verify properties that require multiple tables to be valid
50 FIXME use subtraction based bounds checking to avoid overflows
51 FIXME get rid of metadata_streams and other fields from VerifyContext
52 */
53
54 #ifdef MONO_VERIFIER_DEBUG
55 #define VERIFIER_DEBUG(code) do { code; } while (0)
56 #else
57 #define VERIFIER_DEBUG(code)
58 #endif
59
60 #define INVALID_OFFSET ((guint32)-1)
61 #define INVALID_ADDRESS 0xffffffff
62
63 enum {
64 STAGE_PE,
65 STAGE_CLI,
66 STAGE_TABLES
67 };
68
69 enum {
70 IMPORT_TABLE_IDX = 1,
71 RESOURCE_TABLE_IDX = 2,
72 CERTIFICATE_TABLE_IDX = 4,
73 RELOCATION_TABLE_IDX = 5,
74 IAT_IDX = 12,
75 CLI_HEADER_IDX = 14,
76 };
77
78 enum {
79 STRINGS_STREAM,
80 USER_STRINGS_STREAM,
81 BLOB_STREAM,
82 GUID_STREAM,
83 TILDE_STREAM
84 };
85
86
87 #define INVALID_TABLE (0xFF)
88 /*format: number of bits, number of tables, tables{n. tables} */
89 const static unsigned char coded_index_desc[] = {
90 #define TYPEDEF_OR_REF_DESC (0)
91 2, /*bits*/
92 3, /*tables*/
93 MONO_TABLE_TYPEDEF,
94 MONO_TABLE_TYPEREF,
95 MONO_TABLE_TYPESPEC,
96
97 #define HAS_CONSTANT_DESC (TYPEDEF_OR_REF_DESC + 5)
98 2, /*bits*/
99 3, /*tables*/
100 MONO_TABLE_FIELD,
101 MONO_TABLE_PARAM,
102 MONO_TABLE_PROPERTY,
103
104 #define HAS_CATTR_DESC (HAS_CONSTANT_DESC + 5)
105 5, /*bits*/
106 20, /*tables*/
107 MONO_TABLE_METHOD,
108 MONO_TABLE_FIELD,
109 MONO_TABLE_TYPEREF,
110 MONO_TABLE_TYPEDEF,
111 MONO_TABLE_PARAM,
112 MONO_TABLE_INTERFACEIMPL,
113 MONO_TABLE_MEMBERREF,
114 MONO_TABLE_MODULE,
115 MONO_TABLE_DECLSECURITY,
116 MONO_TABLE_PROPERTY,
117 MONO_TABLE_EVENT,
118 MONO_TABLE_STANDALONESIG,
119 MONO_TABLE_MODULEREF,
120 MONO_TABLE_TYPESPEC,
121 MONO_TABLE_ASSEMBLY,
122 MONO_TABLE_ASSEMBLYREF,
123 MONO_TABLE_FILE,
124 MONO_TABLE_EXPORTEDTYPE,
125 MONO_TABLE_MANIFESTRESOURCE,
126 MONO_TABLE_GENERICPARAM,
127
128 #define HAS_FIELD_MARSHAL_DESC (HAS_CATTR_DESC + 22)
129 1, /*bits*/
130 2, /*tables*/
131 MONO_TABLE_FIELD,
132 MONO_TABLE_PARAM,
133
134 #define HAS_DECL_SECURITY_DESC (HAS_FIELD_MARSHAL_DESC + 4)
135 2, /*bits*/
136 3, /*tables*/
137 MONO_TABLE_TYPEDEF,
138 MONO_TABLE_METHOD,
139 MONO_TABLE_ASSEMBLY,
140
141 #define MEMBERREF_PARENT_DESC (HAS_DECL_SECURITY_DESC + 5)
142 3, /*bits*/
143 5, /*tables*/
144 MONO_TABLE_TYPEDEF,
145 MONO_TABLE_TYPEREF,
146 MONO_TABLE_MODULEREF,
147 MONO_TABLE_METHOD,
148 MONO_TABLE_TYPESPEC,
149
150 #define HAS_SEMANTICS_DESC (MEMBERREF_PARENT_DESC + 7)
151 1, /*bits*/
152 2, /*tables*/
153 MONO_TABLE_EVENT,
154 MONO_TABLE_PROPERTY,
155
156 #define METHODDEF_OR_REF_DESC (HAS_SEMANTICS_DESC + 4)
157 1, /*bits*/
158 2, /*tables*/
159 MONO_TABLE_METHOD,
160 MONO_TABLE_MEMBERREF,
161
162 #define MEMBER_FORWARDED_DESC (METHODDEF_OR_REF_DESC + 4)
163 1, /*bits*/
164 2, /*tables*/
165 MONO_TABLE_FIELD,
166 MONO_TABLE_METHOD,
167
168 #define IMPLEMENTATION_DESC (MEMBER_FORWARDED_DESC + 4)
169 2, /*bits*/
170 3, /*tables*/
171 MONO_TABLE_FILE,
172 MONO_TABLE_ASSEMBLYREF,
173 MONO_TABLE_EXPORTEDTYPE,
174
175 #define CATTR_TYPE_DESC (IMPLEMENTATION_DESC + 5)
176 3, /*bits*/
177 5, /*tables*/
178 INVALID_TABLE,
179 INVALID_TABLE,
180 MONO_TABLE_METHOD,
181 MONO_TABLE_MEMBERREF,
182 INVALID_TABLE,
183
184 #define RES_SCOPE_DESC (CATTR_TYPE_DESC + 7)
185 2, /*bits*/
186 4, /*tables*/
187 MONO_TABLE_MODULE,
188 MONO_TABLE_MODULEREF,
189 MONO_TABLE_ASSEMBLYREF,
190 MONO_TABLE_TYPEREF,
191
192 #define TYPE_OR_METHODDEF_DESC (RES_SCOPE_DESC + 6)
193 1, /*bits*/
194 2, /*tables*/
195 MONO_TABLE_TYPEDEF,
196 MONO_TABLE_METHOD
197 };
198
199 typedef struct {
200 guint32 rva;
201 guint32 size;
202 guint32 translated_offset;
203 } DataDirectory;
204
205 typedef struct {
206 guint32 offset;
207 guint32 size;
208 } OffsetAndSize;
209
210 typedef struct {
211 guint32 baseRVA;
212 guint32 baseOffset;
213 guint32 size;
214 guint32 rellocationsRVA;
215 guint16 numberOfRelocations;
216 } SectionHeader;
217
218 typedef struct {
219 guint32 row_count;
220 guint32 row_size;
221 guint32 offset;
222 } TableInfo;
223
224 typedef struct {
225 const char *data;
226 guint32 size, token;
227 GSList *errors;
228 int valid;
229 MonoImage *image;
230 gboolean report_error;
231 gboolean report_warning;
232 int stage;
233
234 DataDirectory data_directories [16];
235 guint32 section_count;
236 SectionHeader *sections;
237
238 OffsetAndSize metadata_streams [5]; //offset from begin of the image
239 } VerifyContext;
240
241 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception) \
242 do { \
243 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
244 vinfo->info.status = __status; \
245 vinfo->info.message = ( __msg); \
246 vinfo->exception_type = (__exception); \
247 (__ctx)->errors = g_slist_prepend ((__ctx)->errors, vinfo); \
248 } while (0)
249
250 #define ADD_WARNING(__ctx, __msg) \
251 do { \
252 if ((__ctx)->report_warning) { \
253 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_WARNING, MONO_EXCEPTION_INVALID_PROGRAM); \
254 (__ctx)->valid = 0; \
255 return; \
256 } \
257 } while (0)
258
259 #define ADD_ERROR_NO_RETURN(__ctx, __msg) \
260 do { \
261 if ((__ctx)->report_error) \
262 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
263 (__ctx)->valid = 0; \
264 } while (0)
265
266 #define ADD_ERROR(__ctx, __msg) \
267 do { \
268 if ((__ctx)->report_error) \
269 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
270 (__ctx)->valid = 0; \
271 return; \
272 } while (0)
273
274 #define FAIL(__ctx, __msg) \
275 do { \
276 if ((__ctx)->report_error) \
277 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
278 (__ctx)->valid = 0; \
279 return FALSE; \
280 } while (0)
281
282 #define CHECK_STATE() do { if (!ctx.valid) goto cleanup; } while (0)
283
284 #define CHECK_ERROR() do { if (!ctx->valid) return; } while (0)
285
286 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
287 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
288
289 #if SIZEOF_VOID_P == 4
290 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
291 #else
292 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
293 #endif
294
295 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
296 #define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
297
298 static const char *
dword_align(const char * ptr)299 dword_align (const char *ptr)
300 {
301 #if SIZEOF_VOID_P == 8
302 return (const char *) (((guint64) (ptr + 3)) & ~3);
303 #else
304 return (const char *) (((guint32) (ptr + 3)) & ~3);
305 #endif
306 }
307
308 static void
add_from_mono_error(VerifyContext * ctx,MonoError * error)309 add_from_mono_error (VerifyContext *ctx, MonoError *error)
310 {
311 if (mono_error_ok (error))
312 return;
313
314 ADD_ERROR (ctx, g_strdup (mono_error_get_message (error)));
315 mono_error_cleanup (error);
316 }
317
318 static guint32
pe_signature_offset(VerifyContext * ctx)319 pe_signature_offset (VerifyContext *ctx)
320 {
321 return read32 (ctx->data + 0x3c);
322 }
323
324 static guint32
pe_header_offset(VerifyContext * ctx)325 pe_header_offset (VerifyContext *ctx)
326 {
327 return read32 (ctx->data + 0x3c) + 4;
328 }
329
330 static gboolean
bounds_check_virtual_address(VerifyContext * ctx,guint32 rva,guint32 size)331 bounds_check_virtual_address (VerifyContext *ctx, guint32 rva, guint32 size)
332 {
333 int i;
334
335 if (rva + size < rva) //overflow
336 return FALSE;
337
338 if (ctx->stage > STAGE_PE) {
339 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)ctx->image->image_info;
340 const int top = iinfo->cli_section_count;
341 MonoSectionTable *tables = iinfo->cli_section_tables;
342 int i;
343
344 for (i = 0; i < top; i++) {
345 guint32 base = tables->st_virtual_address;
346 guint32 end = base + tables->st_raw_data_size;
347
348 if (rva >= base && rva + size <= end)
349 return TRUE;
350
351 /*if ((addr >= tables->st_virtual_address) &&
352 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
353
354 return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
355 }*/
356 tables++;
357 }
358 return FALSE;
359 }
360
361 if (!ctx->sections)
362 return FALSE;
363
364 for (i = 0; i < ctx->section_count; ++i) {
365 guint32 base = ctx->sections [i].baseRVA;
366 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
367 if (rva >= base && rva + size <= end)
368 return TRUE;
369 }
370 return FALSE;
371 }
372
373 static gboolean
bounds_check_datadir(DataDirectory * dir,guint32 offset,guint32 size)374 bounds_check_datadir (DataDirectory *dir, guint32 offset, guint32 size)
375 {
376 if (dir->translated_offset > offset)
377 return FALSE;
378 if (dir->size < size)
379 return FALSE;
380 return offset + size <= dir->translated_offset + dir->size;
381 }
382
383 static gboolean
bounds_check_offset(OffsetAndSize * off,guint32 offset,guint32 size)384 bounds_check_offset (OffsetAndSize *off, guint32 offset, guint32 size)
385 {
386 if (off->offset > offset)
387 return FALSE;
388
389 if (off->size < size)
390 return FALSE;
391
392 return offset + size <= off->offset + off->size;
393 }
394
395 static guint32
translate_rva(VerifyContext * ctx,guint32 rva)396 translate_rva (VerifyContext *ctx, guint32 rva)
397 {
398 int i;
399
400 if (ctx->stage > STAGE_PE)
401 return mono_cli_rva_image_map (ctx->image, rva);
402
403 if (!ctx->sections)
404 return FALSE;
405
406 for (i = 0; i < ctx->section_count; ++i) {
407 guint32 base = ctx->sections [i].baseRVA;
408 guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
409 if (rva >= base && rva <= end) {
410 guint32 res = (rva - base) + ctx->sections [i].baseOffset;
411 /* double check */
412 return res >= ctx->size ? INVALID_OFFSET : res;
413 }
414 }
415
416 return INVALID_OFFSET;
417 }
418
419 static void
verify_msdos_header(VerifyContext * ctx)420 verify_msdos_header (VerifyContext *ctx)
421 {
422 guint32 lfanew;
423 if (ctx->size < 128)
424 ADD_ERROR (ctx, g_strdup ("Not enough space for the MS-DOS header"));
425 if (ctx->data [0] != 0x4d || ctx->data [1] != 0x5a)
426 ADD_ERROR (ctx, g_strdup ("Invalid MS-DOS watermark"));
427 lfanew = pe_signature_offset (ctx);
428 if (lfanew > ctx->size - 4)
429 ADD_ERROR (ctx, g_strdup ("MS-DOS lfanew offset points to outside of the file"));
430 }
431
432 static void
verify_pe_header(VerifyContext * ctx)433 verify_pe_header (VerifyContext *ctx)
434 {
435 guint32 offset = pe_signature_offset (ctx);
436 const char *pe_header = ctx->data + offset;
437 if (pe_header [0] != 'P' || pe_header [1] != 'E' ||pe_header [2] != 0 ||pe_header [3] != 0)
438 ADD_ERROR (ctx, g_strdup ("Invalid PE header watermark"));
439 pe_header += 4;
440 offset += 4;
441
442 if (offset > ctx->size - 20)
443 ADD_ERROR (ctx, g_strdup ("File with truncated pe header"));
444 if (read16 (pe_header) != 0x14c)
445 ADD_ERROR (ctx, g_strdup ("Invalid PE header Machine value"));
446 }
447
448 static void
verify_pe_optional_header(VerifyContext * ctx)449 verify_pe_optional_header (VerifyContext *ctx)
450 {
451 guint32 offset = pe_header_offset (ctx);
452 guint32 header_size, file_alignment;
453 const char *pe_header = ctx->data + offset;
454 const char *pe_optional_header = pe_header + 20;
455
456 header_size = read16 (pe_header + 16);
457 offset += 20;
458
459 if (header_size < 2) /*must be at least 2 or we won't be able to read magic*/
460 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
461
462 if (offset > ctx->size - header_size || header_size > ctx->size)
463 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
464
465 if (read16 (pe_optional_header) == 0x10b) {
466 if (header_size != 224)
467 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header size %d", header_size));
468
469 /* LAMESPEC MS plays around this value and ignore it during validation
470 if (read32 (pe_optional_header + 28) != 0x400000)
471 ADD_ERROR (ctx, g_strdup_printf ("Invalid Image base %x", read32 (pe_optional_header + 28)));*/
472 if (read32 (pe_optional_header + 32) != 0x2000)
473 ADD_ERROR (ctx, g_strdup_printf ("Invalid Section Aligmnent %x", read32 (pe_optional_header + 32)));
474 file_alignment = read32 (pe_optional_header + 36);
475 if (file_alignment != 0x200 && file_alignment != 0x1000)
476 ADD_ERROR (ctx, g_strdup_printf ("Invalid file Aligmnent %x", file_alignment));
477 /* All the junk in the middle is irrelevant, specially for mono. */
478 if (read32 (pe_optional_header + 92) > 0x10)
479 ADD_ERROR (ctx, g_strdup_printf ("Too many data directories %x", read32 (pe_optional_header + 92)));
480 } else {
481 if (read16 (pe_optional_header) == 0x20B)
482 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle PE32+"));
483 else
484 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header magic %d", read16 (pe_optional_header)));
485 }
486 }
487
488 static void
load_section_table(VerifyContext * ctx)489 load_section_table (VerifyContext *ctx)
490 {
491 int i;
492 SectionHeader *sections;
493 guint32 offset = pe_header_offset (ctx);
494 const char *ptr = ctx->data + offset;
495 guint16 num_sections = ctx->section_count = read16 (ptr + 2);
496
497 offset += 244;/*FIXME, this constant is different under PE32+*/
498 ptr += 244;
499
500 if (num_sections * 40 > ctx->size - offset)
501 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
502
503 sections = ctx->sections = g_new0 (SectionHeader, num_sections);
504 for (i = 0; i < num_sections; ++i) {
505 sections [i].size = read32 (ptr + 8);
506 sections [i].baseRVA = read32 (ptr + 12);
507 sections [i].baseOffset = read32 (ptr + 20);
508 sections [i].rellocationsRVA = read32 (ptr + 24);
509 sections [i].numberOfRelocations = read16 (ptr + 32);
510 ptr += 40;
511 }
512
513 ptr = ctx->data + offset; /*reset it to the beggining*/
514 for (i = 0; i < num_sections; ++i) {
515 guint32 raw_size, flags;
516 if (sections [i].baseOffset == 0)
517 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with intialized data only"));
518 if (sections [i].baseOffset >= ctx->size)
519 ADD_ERROR (ctx, g_strdup_printf ("Invalid PointerToRawData %x points beyond EOF", sections [i].baseOffset));
520 if (sections [i].size > ctx->size - sections [i].baseOffset)
521 ADD_ERROR (ctx, g_strdup ("Invalid VirtualSize points beyond EOF"));
522
523 raw_size = read32 (ptr + 16);
524 if (raw_size < sections [i].size)
525 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with SizeOfRawData < VirtualSize"));
526
527 if (raw_size > ctx->size - sections [i].baseOffset)
528 ADD_ERROR (ctx, g_strdup_printf ("Invalid SizeOfRawData %x points beyond EOF", raw_size));
529
530 if (sections [i].rellocationsRVA || sections [i].numberOfRelocations)
531 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't handle section relocation"));
532
533 flags = read32 (ptr + 36);
534 /*TODO 0xFE0000E0 is all flags from cil-coff.h OR'd. Make it a less magical number*/
535 if (flags == 0 || (flags & ~0xFE0000E0) != 0)
536 ADD_ERROR (ctx, g_strdup_printf ("Invalid section flags %x", flags));
537
538 ptr += 40;
539 }
540 }
541
542 static gboolean
is_valid_data_directory(int i)543 is_valid_data_directory (int i)
544 {
545 /*LAMESPEC 4 == certificate 6 == debug, MS uses both*/
546 return i == 1 || i == 2 || i == 5 || i == 12 || i == 14 || i == 4 || i == 6;
547 }
548
549 static void
load_data_directories(VerifyContext * ctx)550 load_data_directories (VerifyContext *ctx)
551 {
552 guint32 offset = pe_header_offset (ctx) + 116; /*FIXME, this constant is different under PE32+*/
553 const char *ptr = ctx->data + offset;
554 int i;
555
556 for (i = 0; i < 16; ++i) {
557 guint32 rva = read32 (ptr);
558 guint32 size = read32 (ptr + 4);
559
560 /*LAMESPEC the authenticode data directory format is different. We don't support CAS, so lets ignore for now.*/
561 if (i == CERTIFICATE_TABLE_IDX) {
562 ptr += 8;
563 continue;
564 }
565 if ((rva != 0 || size != 0) && !is_valid_data_directory (i))
566 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d", i));
567
568 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
569 ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d rva/size pair %x/%x", i, rva, size));
570
571 ctx->data_directories [i].rva = rva;
572 ctx->data_directories [i].size = size;
573 ctx->data_directories [i].translated_offset = translate_rva (ctx, rva);
574
575 ptr += 8;
576 }
577 }
578
579 #define SIZE_OF_MSCOREE (sizeof ("mscoree.dll"))
580
581 #define SIZE_OF_CORMAIN (sizeof ("_CorExeMain"))
582
583 static void
verify_hint_name_table(VerifyContext * ctx,guint32 import_rva,const char * table_name)584 verify_hint_name_table (VerifyContext *ctx, guint32 import_rva, const char *table_name)
585 {
586 const char *ptr;
587 guint32 hint_table_rva;
588
589 import_rva = translate_rva (ctx, import_rva);
590 g_assert (import_rva != INVALID_OFFSET);
591
592 hint_table_rva = read32 (ctx->data + import_rva);
593 if (!bounds_check_virtual_address (ctx, hint_table_rva, SIZE_OF_CORMAIN + 2))
594 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint/Name rva %d for %s", hint_table_rva, table_name));
595
596 hint_table_rva = translate_rva (ctx, hint_table_rva);
597 g_assert (hint_table_rva != INVALID_OFFSET);
598 ptr = ctx->data + hint_table_rva + 2;
599
600 if (memcmp ("_CorExeMain", ptr, SIZE_OF_CORMAIN) && memcmp ("_CorDllMain", ptr, SIZE_OF_CORMAIN)) {
601 char name[SIZE_OF_CORMAIN];
602 memcpy (name, ptr, SIZE_OF_CORMAIN);
603 name [SIZE_OF_CORMAIN - 1] = 0;
604 ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint / Name: '%s'", name));
605 }
606 }
607
608 static void
verify_import_table(VerifyContext * ctx)609 verify_import_table (VerifyContext *ctx)
610 {
611 DataDirectory it = ctx->data_directories [IMPORT_TABLE_IDX];
612 guint32 offset = it.translated_offset;
613 const char *ptr = ctx->data + offset;
614 guint32 name_rva, ilt_rva, iat_rva;
615
616 g_assert (offset != INVALID_OFFSET);
617
618 if (it.size < 40)
619 ADD_ERROR (ctx, g_strdup_printf ("Import table size %d is smaller than 40", it.size));
620
621 ilt_rva = read32 (ptr);
622 if (ilt_rva && !bounds_check_virtual_address (ctx, ilt_rva, 8))
623 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Lookup Table rva %x", ilt_rva));
624
625 name_rva = read32 (ptr + 12);
626 if (name_rva && !bounds_check_virtual_address (ctx, name_rva, SIZE_OF_MSCOREE))
627 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name rva %x", name_rva));
628
629 iat_rva = read32 (ptr + 16);
630 if (iat_rva) {
631 if (!bounds_check_virtual_address (ctx, iat_rva, 8))
632 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Address Table rva %x", iat_rva));
633
634 if (iat_rva != ctx->data_directories [IAT_IDX].rva)
635 ADD_ERROR (ctx, g_strdup_printf ("Import Address Table rva %x different from data directory entry %x", read32 (ptr + 16), ctx->data_directories [IAT_IDX].rva));
636 }
637
638 if (name_rva) {
639 name_rva = translate_rva (ctx, name_rva);
640 g_assert (name_rva != INVALID_OFFSET);
641 ptr = ctx->data + name_rva;
642
643 if (memcmp ("mscoree.dll", ptr, SIZE_OF_MSCOREE)) {
644 char name[SIZE_OF_MSCOREE];
645 memcpy (name, ptr, SIZE_OF_MSCOREE);
646 name [SIZE_OF_MSCOREE - 1] = 0;
647 ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name: '%s'", name));
648 }
649 }
650
651 if (ilt_rva) {
652 verify_hint_name_table (ctx, ilt_rva, "Import Lookup Table");
653 CHECK_ERROR ();
654 }
655
656 if (iat_rva)
657 verify_hint_name_table (ctx, iat_rva, "Import Address Table");
658 }
659
660 static void
verify_resources_table(VerifyContext * ctx)661 verify_resources_table (VerifyContext *ctx)
662 {
663 DataDirectory it = ctx->data_directories [RESOURCE_TABLE_IDX];
664 guint32 offset;
665 guint16 named_entries, id_entries;
666 const char *ptr;
667
668 if (it.rva == 0)
669 return;
670
671 if (it.size < 16)
672 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));
673
674 offset = it.translated_offset;
675 ptr = ctx->data + offset;
676
677 g_assert (offset != INVALID_OFFSET);
678
679 named_entries = read16 (ptr + 12);
680 id_entries = read16 (ptr + 14);
681
682 if ((named_entries + id_entries) * 8 + 16 > it.size)
683 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));
684
685 /* XXX at least one unmanaged resource is added due to a call to AssemblyBuilder::DefineVersionInfoResource ()
686 if (named_entries || id_entries)
687 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support full verification of PECOFF resources"));
688 */
689 }
690
691 /*----------nothing from here on can use data_directory---*/
692
693 static DataDirectory
get_data_dir(VerifyContext * ctx,int idx)694 get_data_dir (VerifyContext *ctx, int idx)
695 {
696 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)ctx->image->image_info;
697 MonoPEDirEntry *entry= &iinfo->cli_header.datadir.pe_export_table;
698 DataDirectory res;
699
700 entry += idx;
701 res.rva = entry->rva;
702 res.size = entry->size;
703 res.translated_offset = translate_rva (ctx, res.rva);
704 return res;
705
706 }
707 static void
verify_cli_header(VerifyContext * ctx)708 verify_cli_header (VerifyContext *ctx)
709 {
710 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
711 guint32 offset;
712 const char *ptr;
713 int i;
714
715 if (it.rva == 0)
716 ADD_ERROR (ctx, g_strdup_printf ("CLI header missing"));
717
718 if (it.size != 72)
719 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size in data directory %d must be 72", it.size));
720
721 offset = it.translated_offset;
722 ptr = ctx->data + offset;
723
724 g_assert (offset != INVALID_OFFSET);
725
726 if (read16 (ptr) != 72)
727 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size %d must be 72", read16 (ptr)));
728
729 if (!bounds_check_virtual_address (ctx, read32 (ptr + 8), read32 (ptr + 12)))
730 ADD_ERROR (ctx, g_strdup_printf ("Invalid medatata section rva/size pair %x/%x", read32 (ptr + 8), read32 (ptr + 12)));
731
732
733 if (!read32 (ptr + 8) || !read32 (ptr + 12))
734 ADD_ERROR (ctx, g_strdup_printf ("Missing medatata section in the CLI header"));
735
736 if ((read32 (ptr + 16) & ~0x0003000B) != 0)
737 ADD_ERROR (ctx, g_strdup_printf ("Invalid CLI header flags"));
738
739 ptr += 24;
740 for (i = 0; i < 6; ++i) {
741 guint32 rva = read32 (ptr);
742 guint32 size = read32 (ptr + 4);
743
744 if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
745 ADD_ERROR (ctx, g_strdup_printf ("Invalid cli section %i rva/size pair %x/%x", i, rva, size));
746
747 ptr += 8;
748
749 if (rva && i > 1)
750 ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't support cli header section %d", i));
751 }
752 }
753
754 static guint32
pad4(guint32 offset)755 pad4 (guint32 offset)
756 {
757 if (offset & 0x3) //pad to the next 4 byte boundary
758 offset = (offset & ~0x3) + 4;
759 return offset;
760 }
761
762 static void
verify_metadata_header(VerifyContext * ctx)763 verify_metadata_header (VerifyContext *ctx)
764 {
765 int i;
766 DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
767 guint32 offset, section_count;
768 const char *ptr;
769
770 offset = it.translated_offset;
771 ptr = ctx->data + offset;
772 g_assert (offset != INVALID_OFFSET);
773
774 //build a directory entry for the metadata root
775 ptr += 8;
776 it.rva = read32 (ptr);
777 ptr += 4;
778 it.size = read32 (ptr);
779 it.translated_offset = offset = translate_rva (ctx, it.rva);
780
781 ptr = ctx->data + offset;
782 g_assert (offset != INVALID_OFFSET);
783
784 if (it.size < 20)
785 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small %d (at least 20 bytes required for initial decoding)", it.size));
786
787 if (read32 (ptr) != 0x424A5342)
788 ADD_ERROR (ctx, g_strdup_printf ("Invalid metadata signature, expected 0x424A5342 but got %08x", read32 (ptr)));
789
790 offset = pad4 (offset + 16 + read32 (ptr + 12));
791
792 if (!bounds_check_datadir (&it, offset, 4))
793 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));
794
795 ptr = ctx->data + offset; //move to streams header
796
797 section_count = read16 (ptr + 2);
798 if (section_count < 2)
799 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section must have at least 2 streams (#~ and #GUID)"));
800
801 ptr += 4;
802 offset += 4;
803
804 for (i = 0; i < section_count; ++i) {
805 guint32 stream_off, stream_size;
806 int string_size, stream_idx;
807
808 if (!bounds_check_datadir (&it, offset, 8))
809 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));
810
811 stream_off = it.translated_offset + read32 (ptr);
812 stream_size = read32 (ptr + 4);
813
814 if (!bounds_check_datadir (&it, stream_off, stream_size))
815 ADD_ERROR (ctx, g_strdup_printf ("Invalid stream header %d offset/size pair %x/%x", 0, stream_off, stream_size));
816
817 ptr += 8;
818 offset += 8;
819
820 for (string_size = 0; string_size < 32; ++string_size) {
821 if (!bounds_check_datadir (&it, offset++, 1))
822 ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small to decode stream header %d name", i));
823 if (!ptr [string_size])
824 break;
825 }
826
827 if (ptr [string_size])
828 ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d name larger than 32 bytes", i));
829
830 if (!strncmp ("#Strings", ptr, 9))
831 stream_idx = STRINGS_STREAM;
832 else if (!strncmp ("#US", ptr, 4))
833 stream_idx = USER_STRINGS_STREAM;
834 else if (!strncmp ("#Blob", ptr, 6))
835 stream_idx = BLOB_STREAM;
836 else if (!strncmp ("#GUID", ptr, 6))
837 stream_idx = GUID_STREAM;
838 else if (!strncmp ("#~", ptr, 3))
839 stream_idx = TILDE_STREAM;
840 else {
841 ADD_WARNING (ctx, g_strdup_printf ("Metadata stream header %d invalid name %s", i, ptr));
842 offset = pad4 (offset);
843 ptr = ctx->data + offset;
844 continue;
845 }
846
847 if (ctx->metadata_streams [stream_idx].offset != 0)
848 ADD_ERROR (ctx, g_strdup_printf ("Duplicated metadata stream header %s", ptr));
849
850 ctx->metadata_streams [stream_idx].offset = stream_off;
851 ctx->metadata_streams [stream_idx].size = stream_size;
852
853 offset = pad4 (offset);
854 ptr = ctx->data + offset;
855 }
856
857 if (!ctx->metadata_streams [TILDE_STREAM].size)
858 ADD_ERROR (ctx, g_strdup_printf ("Metadata #~ stream missing"));
859 if (!ctx->metadata_streams [GUID_STREAM].size)
860 ADD_ERROR (ctx, g_strdup_printf ("Metadata guid stream missing"));
861 }
862
863 static void
verify_tables_schema(VerifyContext * ctx)864 verify_tables_schema (VerifyContext *ctx)
865 {
866 OffsetAndSize tables_area = ctx->metadata_streams [TILDE_STREAM];
867 unsigned offset = tables_area.offset;
868 const char *ptr = ctx->data + offset;
869 guint64 valid_tables;
870 guint32 count;
871 int i;
872
873 if (tables_area.size < 24)
874 ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for initial decoding (requires 24 bytes)", tables_area.size));
875
876 if (ptr [4] != 2 && ptr [4] != 1)
877 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata major version %d, expected 2", ptr [4]));
878 if (ptr [5] != 0)
879 ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata minor version %d, expected 0", ptr [5]));
880
881 if ((ptr [6] & ~0x7) != 0)
882 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]));
883
884 valid_tables = read64 (ptr + 8);
885 count = 0;
886 for (i = 0; i < 64; ++i) {
887 if (!(valid_tables & ((guint64)1 << i)))
888 continue;
889
890 /*MS Extensions: 0x3 0x5 0x7 0x13 0x16
891 Unused: 0x1E 0x1F 0x2D-0x3F
892 We don't care about the MS extensions.*/
893 if (i == 0x3 || i == 0x5 || i == 0x7 || i == 0x13 || i == 0x16)
894 ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support MS specific table %x", i));
895 if (i == 0x1E || i == 0x1F || i >= 0x2D)
896 ADD_ERROR (ctx, g_strdup_printf ("Invalid table %x", i));
897 ++count;
898 }
899
900 if (tables_area.size < 24 + count * 4)
901 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));
902 ptr += 24;
903
904 for (i = 0; i < 64; ++i) {
905 if (valid_tables & ((guint64)1 << i)) {
906 guint32 row_count = read32 (ptr);
907 if (row_count > (1 << 24) - 1)
908 ADD_ERROR (ctx, g_strdup_printf ("Invalid Table %d row count: %d. Mono only supports 16777215 rows", i, row_count));
909 ptr += 4;
910 }
911 }
912 }
913
914 /*----------nothing from here on can use data_directory or metadata_streams ---*/
915
916 static guint32
get_col_offset(VerifyContext * ctx,int table,int column)917 get_col_offset (VerifyContext *ctx, int table, int column)
918 {
919 guint32 bitfield = ctx->image->tables [table].size_bitfield;
920 guint32 offset = 0;
921
922 while (column-- > 0)
923 offset += mono_metadata_table_size (bitfield, column);
924
925 return offset;
926 }
927
928 static guint32
get_col_size(VerifyContext * ctx,int table,int column)929 get_col_size (VerifyContext *ctx, int table, int column)
930 {
931 return mono_metadata_table_size (ctx->image->tables [table].size_bitfield, column);
932 }
933
934 static OffsetAndSize
get_metadata_stream(VerifyContext * ctx,MonoStreamHeader * header)935 get_metadata_stream (VerifyContext *ctx, MonoStreamHeader *header)
936 {
937 OffsetAndSize res;
938 res.offset = header->data - ctx->data;
939 res.size = header->size;
940
941 return res;
942 }
943
944 static gboolean
is_valid_string_full_with_image(MonoImage * image,guint32 offset,gboolean allow_empty)945 is_valid_string_full_with_image (MonoImage *image, guint32 offset, gboolean allow_empty)
946 {
947 guint32 heap_offset = (char*)image->heap_strings.data - image->raw_data;
948 guint32 heap_size = image->heap_strings.size;
949
950 glong length;
951 const char *data = image->raw_data + heap_offset;
952
953 if (offset >= heap_size)
954 return FALSE;
955 if (CHECK_ADDP_OVERFLOW_UN (data, offset))
956 return FALSE;
957
958 if (!mono_utf8_validate_and_len_with_bounds (data + offset, heap_size - offset, &length, NULL))
959 return FALSE;
960 return allow_empty || length > 0;
961 }
962
963
964 static gboolean
is_valid_string_full(VerifyContext * ctx,guint32 offset,gboolean allow_empty)965 is_valid_string_full (VerifyContext *ctx, guint32 offset, gboolean allow_empty)
966 {
967 return is_valid_string_full_with_image (ctx->image, offset, allow_empty);
968 }
969
970 static gboolean
is_valid_string(VerifyContext * ctx,guint32 offset)971 is_valid_string (VerifyContext *ctx, guint32 offset)
972 {
973 return is_valid_string_full (ctx, offset, TRUE);
974 }
975
976 static gboolean
is_valid_non_empty_string(VerifyContext * ctx,guint32 offset)977 is_valid_non_empty_string (VerifyContext *ctx, guint32 offset)
978 {
979 return is_valid_string_full (ctx, offset, FALSE);
980 }
981
982 static gboolean
is_valid_guid(VerifyContext * ctx,guint32 offset)983 is_valid_guid (VerifyContext *ctx, guint32 offset)
984 {
985 OffsetAndSize guids = get_metadata_stream (ctx, &ctx->image->heap_guid);
986 return guids.size >= 8 && guids.size - 8 >= offset;
987 }
988
989 static guint32
get_coded_index_token(int token_kind,guint32 coded_token)990 get_coded_index_token (int token_kind, guint32 coded_token)
991 {
992 guint32 bits = coded_index_desc [token_kind];
993 return coded_token >> bits;
994 }
995
996 static guint32
get_coded_index_table(int kind,guint32 coded_token)997 get_coded_index_table (int kind, guint32 coded_token)
998 {
999 guint32 idx, bits = coded_index_desc [kind];
1000 kind += 2;
1001 idx = coded_token & ((1 << bits) - 1);
1002 return coded_index_desc [kind + idx];
1003 }
1004
1005 static guint32
make_coded_token(int kind,guint32 table,guint32 table_idx)1006 make_coded_token (int kind, guint32 table, guint32 table_idx)
1007 {
1008 guint32 bits = coded_index_desc [kind++];
1009 guint32 tables = coded_index_desc [kind++];
1010 guint32 i;
1011 for (i = 0; i < tables; ++i) {
1012 if (coded_index_desc [kind++] == table)
1013 return ((table_idx + 1) << bits) | i;
1014 }
1015 g_assert_not_reached ();
1016 return -1;
1017 }
1018
1019 static gboolean
is_valid_coded_index_with_image(MonoImage * image,int token_kind,guint32 coded_token)1020 is_valid_coded_index_with_image (MonoImage *image, int token_kind, guint32 coded_token)
1021 {
1022 guint32 bits = coded_index_desc [token_kind++];
1023 guint32 table_count = coded_index_desc [token_kind++];
1024 guint32 table = coded_token & ((1 << bits) - 1);
1025 guint32 token = coded_token >> bits;
1026
1027 if (table >= table_count)
1028 return FALSE;
1029
1030 /*token_kind points to the first table idx*/
1031 table = coded_index_desc [token_kind + table];
1032
1033 if (table == INVALID_TABLE)
1034 return FALSE;
1035 return token <= image->tables [table].rows;
1036 }
1037
1038 static gboolean
is_valid_coded_index(VerifyContext * ctx,int token_kind,guint32 coded_token)1039 is_valid_coded_index (VerifyContext *ctx, int token_kind, guint32 coded_token)
1040 {
1041 return is_valid_coded_index_with_image (ctx->image, token_kind, coded_token);
1042 }
1043
1044 typedef struct {
1045 guint32 token;
1046 guint32 col_size;
1047 guint32 col_offset;
1048 MonoTableInfo *table;
1049 } RowLocator;
1050
1051 static int
token_locator(const void * a,const void * b)1052 token_locator (const void *a, const void *b)
1053 {
1054 RowLocator *loc = (RowLocator *)a;
1055 unsigned const char *row = (unsigned const char *)b;
1056 guint32 token = loc->col_size == 2 ? read16 (row + loc->col_offset) : read32 (row + loc->col_offset);
1057
1058 VERIFIER_DEBUG ( printf ("\tfound token %x at idx %d\n", token, ((const char*)row - loc->table->base) / loc->table->row_size) );
1059 return (int)loc->token - (int)token;
1060 }
1061
1062 static int
search_sorted_table(VerifyContext * ctx,int table,int column,guint32 coded_token)1063 search_sorted_table (VerifyContext *ctx, int table, int column, guint32 coded_token)
1064 {
1065 MonoTableInfo *tinfo = &ctx->image->tables [table];
1066 RowLocator locator;
1067 const char *res, *base;
1068 locator.token = coded_token;
1069 locator.col_offset = get_col_offset (ctx, table, column);
1070 locator.col_size = get_col_size (ctx, table, column);
1071 locator.table = tinfo;
1072
1073 base = tinfo->base;
1074
1075 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) );
1076 res = (const char *)mono_binary_search (&locator, base, tinfo->rows, tinfo->row_size, token_locator);
1077 if (!res)
1078 return -1;
1079
1080 return (res - base) / tinfo->row_size;
1081 }
1082
1083 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1084 static const char*
get_string_ptr(VerifyContext * ctx,guint offset)1085 get_string_ptr (VerifyContext *ctx, guint offset)
1086 {
1087 return ctx->image->heap_strings.data + offset;
1088 }
1089
1090 /*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
1091 static int
string_cmp(VerifyContext * ctx,const char * str,guint offset)1092 string_cmp (VerifyContext *ctx, const char *str, guint offset)
1093 {
1094 if (offset == 0)
1095 return strcmp (str, "");
1096
1097 return strcmp (str, get_string_ptr (ctx, offset));
1098 }
1099
1100 static gboolean
mono_verifier_is_corlib(MonoImage * image)1101 mono_verifier_is_corlib (MonoImage *image)
1102 {
1103 gboolean trusted_location = !mono_security_core_clr_enabled () ?
1104 TRUE : mono_security_core_clr_is_platform_image (image);
1105
1106 return trusted_location && image->module_name && !strcmp ("mscorlib.dll", image->module_name);
1107 }
1108
1109 static gboolean
typedef_is_system_object(VerifyContext * ctx,guint32 * data)1110 typedef_is_system_object (VerifyContext *ctx, guint32 *data)
1111 {
1112 return mono_verifier_is_corlib (ctx->image) && !string_cmp (ctx, "System", data [MONO_TYPEDEF_NAMESPACE]) && !string_cmp (ctx, "Object", data [MONO_TYPEDEF_NAME]);
1113 }
1114
1115 static gboolean
decode_value(const char * _ptr,unsigned available,unsigned * value,unsigned * size)1116 decode_value (const char *_ptr, unsigned available, unsigned *value, unsigned *size)
1117 {
1118 unsigned char b;
1119 const unsigned char *ptr = (const unsigned char *)_ptr;
1120
1121 if (!available)
1122 return FALSE;
1123
1124 b = *ptr;
1125 *value = *size = 0;
1126
1127 if ((b & 0x80) == 0) {
1128 *size = 1;
1129 *value = b;
1130 } else if ((b & 0x40) == 0) {
1131 if (available < 2)
1132 return FALSE;
1133 *size = 2;
1134 *value = ((b & 0x3f) << 8 | ptr [1]);
1135 } else {
1136 if (available < 4)
1137 return FALSE;
1138 *size = 4;
1139 *value = ((b & 0x1f) << 24) |
1140 (ptr [1] << 16) |
1141 (ptr [2] << 8) |
1142 ptr [3];
1143 }
1144
1145 return TRUE;
1146 }
1147
1148 static gboolean
decode_signature_header(VerifyContext * ctx,guint32 offset,guint32 * size,const char ** first_byte)1149 decode_signature_header (VerifyContext *ctx, guint32 offset, guint32 *size, const char **first_byte)
1150 {
1151 MonoStreamHeader blob = ctx->image->heap_blob;
1152 guint32 value, enc_size;
1153
1154 if (offset >= blob.size)
1155 return FALSE;
1156
1157 if (!decode_value (blob.data + offset, blob.size - offset, &value, &enc_size))
1158 return FALSE;
1159
1160 if (CHECK_ADD4_OVERFLOW_UN (offset, enc_size))
1161 return FALSE;
1162
1163 offset += enc_size;
1164
1165 if (ADD_IS_GREATER_OR_OVF (offset, value, blob.size))
1166 return FALSE;
1167
1168 *size = value;
1169 *first_byte = blob.data + offset;
1170 return TRUE;
1171 }
1172
1173 static gboolean
safe_read(const char ** _ptr,const char * limit,unsigned * dest,int size)1174 safe_read (const char **_ptr, const char *limit, unsigned *dest, int size)
1175 {
1176 const char *ptr = *_ptr;
1177 if (ptr + size > limit)
1178 return FALSE;
1179 switch (size) {
1180 case 1:
1181 *dest = *((guint8*)ptr);
1182 ++ptr;
1183 break;
1184 case 2:
1185 *dest = read16 (ptr);
1186 ptr += 2;
1187 break;
1188 case 4:
1189 *dest = read32 (ptr);
1190 ptr += 4;
1191 break;
1192 }
1193 *_ptr = ptr;
1194 return TRUE;
1195 }
1196
1197 static gboolean
safe_read_compressed_int(const char ** _ptr,const char * limit,unsigned * dest)1198 safe_read_compressed_int (const char **_ptr, const char *limit, unsigned *dest)
1199 {
1200 unsigned size = 0;
1201 const char *ptr = *_ptr;
1202 gboolean res = decode_value (ptr, limit - ptr, dest, &size);
1203 *_ptr = ptr + size;
1204 return res;
1205 }
1206
1207 #define safe_read8(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 1)
1208 #define safe_read_cint(VAR, PTR, LIMIT) safe_read_compressed_int (&PTR, LIMIT, &VAR)
1209 #define safe_read16(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 2)
1210 #define safe_read32(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 4)
1211
1212 static gboolean
1213 parse_type (VerifyContext *ctx, const char **_ptr, const char *end);
1214
1215 static gboolean
1216 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged);
1217
1218 static gboolean
parse_custom_mods(VerifyContext * ctx,const char ** _ptr,const char * end)1219 parse_custom_mods (VerifyContext *ctx, const char **_ptr, const char *end)
1220 {
1221 const char *ptr = *_ptr;
1222 unsigned type = 0;
1223 unsigned token = 0;
1224
1225 while (TRUE) {
1226 if (!safe_read8 (type, ptr, end))
1227 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the type"));
1228
1229 if (type != MONO_TYPE_CMOD_REQD && type != MONO_TYPE_CMOD_OPT) {
1230 --ptr;
1231 break;
1232 }
1233
1234 if (!safe_read_cint (token, ptr, end))
1235 FAIL (ctx, g_strdup ("CustomMod: Not enough room for the token"));
1236
1237 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token) || !get_coded_index_token (TYPEDEF_OR_REF_DESC, token))
1238 FAIL (ctx, g_strdup_printf ("CustomMod: invalid TypeDefOrRef token %x", token));
1239 }
1240
1241 *_ptr = ptr;
1242 return TRUE;
1243 }
1244
1245 static gboolean
parse_array_shape(VerifyContext * ctx,const char ** _ptr,const char * end)1246 parse_array_shape (VerifyContext *ctx, const char **_ptr, const char *end)
1247 {
1248 const char *ptr = *_ptr;
1249 unsigned val = 0;
1250 unsigned size, num, i;
1251
1252 if (!safe_read8 (val, ptr, end))
1253 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for Rank"));
1254
1255 if (val == 0)
1256 FAIL (ctx, g_strdup ("ArrayShape: Invalid shape with zero Rank"));
1257
1258 if (!safe_read_cint (size, ptr, end))
1259 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumSizes"));
1260
1261 for (i = 0; i < size; ++i) {
1262 if (!safe_read_cint (num, ptr, end))
1263 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for Size of rank %d", i + 1));
1264 }
1265
1266 if (!safe_read_cint (size, ptr, end))
1267 FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumLoBounds"));
1268
1269 for (i = 0; i < size; ++i) {
1270 if (!safe_read_cint (num, ptr, end))
1271 FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for LoBound of rank %d", i + 1));
1272 }
1273
1274 *_ptr = ptr;
1275 return TRUE;
1276 }
1277
1278 static gboolean
parse_generic_inst(VerifyContext * ctx,const char ** _ptr,const char * end)1279 parse_generic_inst (VerifyContext *ctx, const char **_ptr, const char *end)
1280 {
1281 const char *ptr = *_ptr;
1282 unsigned type;
1283 unsigned count, token, i;
1284
1285 if (!safe_read8 (type, ptr, end))
1286 FAIL (ctx, g_strdup ("GenericInst: Not enough room for kind"));
1287
1288 if (type != MONO_TYPE_CLASS && type != MONO_TYPE_VALUETYPE)
1289 FAIL (ctx, g_strdup_printf ("GenericInst: Invalid GenericInst kind %x\n", type));
1290
1291 if (!safe_read_cint (token, ptr, end))
1292 FAIL (ctx, g_strdup ("GenericInst: Not enough room for type token"));
1293
1294 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token) || !get_coded_index_token (TYPEDEF_OR_REF_DESC, token))
1295 FAIL (ctx, g_strdup_printf ("GenericInst: invalid TypeDefOrRef token %x", token));
1296
1297 if (ctx->token) {
1298 if (mono_metadata_token_index (ctx->token) == get_coded_index_token (TYPEDEF_OR_REF_DESC, token) &&
1299 mono_metadata_token_table (ctx->token) == get_coded_index_table (TYPEDEF_OR_REF_DESC, token))
1300 FAIL (ctx, g_strdup_printf ("Type: Recurside generic instance specification (%x). A type signature can't reference itself", ctx->token));
1301 }
1302
1303 if (!safe_read_cint (count, ptr, end))
1304 FAIL (ctx, g_strdup ("GenericInst: Not enough room for argument count"));
1305
1306 if (count == 0)
1307 FAIL (ctx, g_strdup ("GenericInst: Zero arguments generic instance"));
1308
1309 for (i = 0; i < count; ++i) {
1310 if (!parse_custom_mods (ctx, &ptr, end))
1311 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1312
1313 if (!parse_type (ctx, &ptr, end))
1314 FAIL (ctx, g_strdup_printf ("GenericInst: invalid generic argument %d", i + 1));
1315 }
1316 *_ptr = ptr;
1317 return TRUE;
1318 }
1319
1320 static gboolean
parse_type(VerifyContext * ctx,const char ** _ptr,const char * end)1321 parse_type (VerifyContext *ctx, const char **_ptr, const char *end)
1322 {
1323 const char *ptr = *_ptr;
1324 unsigned type;
1325 unsigned token = 0;
1326
1327 if (!safe_read8 (type, ptr, end))
1328 FAIL (ctx, g_strdup ("Type: Not enough room for the type"));
1329
1330 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_PTR) ||
1331 (type >= MONO_TYPE_VALUETYPE && type <= MONO_TYPE_GENERICINST) ||
1332 (type >= MONO_TYPE_I && type <= MONO_TYPE_U) ||
1333 (type >= MONO_TYPE_FNPTR && type <= MONO_TYPE_MVAR)))
1334 FAIL (ctx, g_strdup_printf ("Type: Invalid type kind %x\n", type));
1335
1336 switch (type) {
1337 case MONO_TYPE_PTR:
1338 if (!parse_custom_mods (ctx, &ptr, end))
1339 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1340
1341 if (!safe_read8 (type, ptr, end))
1342 FAIL (ctx, g_strdup ("Type: Not enough room to parse the pointer type"));
1343
1344 if (type != MONO_TYPE_VOID) {
1345 --ptr;
1346 if (!parse_type (ctx, &ptr, end))
1347 FAIL (ctx, g_strdup ("Type: Could not parse pointer type"));
1348 }
1349 break;
1350
1351 case MONO_TYPE_VALUETYPE:
1352 case MONO_TYPE_CLASS:
1353 if (!safe_read_cint (token, ptr, end))
1354 FAIL (ctx, g_strdup ("Type: Not enough room for the type token"));
1355
1356 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token) || !get_coded_index_token (TYPEDEF_OR_REF_DESC, token))
1357 FAIL (ctx, g_strdup_printf ("Type: invalid TypeDefOrRef token %x", token));
1358
1359 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, token))
1360 FAIL (ctx, g_strdup_printf ("Type: zero TypeDefOrRef token %x", token));
1361 if (ctx->token) {
1362 if (mono_metadata_token_index (ctx->token) == get_coded_index_token (TYPEDEF_OR_REF_DESC, token) &&
1363 mono_metadata_token_table (ctx->token) == get_coded_index_table (TYPEDEF_OR_REF_DESC, token))
1364 FAIL (ctx, g_strdup_printf ("Type: Recursive type specification (%x). A type signature can't reference itself", ctx->token));
1365 }
1366 break;
1367
1368 case MONO_TYPE_VAR:
1369 case MONO_TYPE_MVAR:
1370 if (!safe_read_cint (token, ptr, end))
1371 FAIL (ctx, g_strdup ("Type: Not enough room for to decode generic argument number"));
1372 break;
1373
1374 case MONO_TYPE_ARRAY:
1375 if (!parse_type (ctx, &ptr, end))
1376 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1377 if (!parse_array_shape (ctx, &ptr, end))
1378 FAIL (ctx, g_strdup ("Type: Could not parse array shape"));
1379 break;
1380
1381 case MONO_TYPE_GENERICINST:
1382 if (!parse_generic_inst (ctx, &ptr, end))
1383 FAIL (ctx, g_strdup ("Type: Could not parse generic inst"));
1384 break;
1385
1386 case MONO_TYPE_FNPTR:
1387 if (!parse_method_signature (ctx, &ptr, end, TRUE, TRUE))
1388 FAIL (ctx, g_strdup ("Type: Could not parse method pointer signature"));
1389 break;
1390
1391 case MONO_TYPE_SZARRAY:
1392 if (!parse_custom_mods (ctx, &ptr, end))
1393 FAIL (ctx, g_strdup ("Type: Failed to parse array element custom attr"));
1394 if (!parse_type (ctx, &ptr, end))
1395 FAIL (ctx, g_strdup ("Type: Could not parse array type"));
1396 break;
1397 }
1398 *_ptr = ptr;
1399 return TRUE;
1400 }
1401
1402 static gboolean
parse_return_type(VerifyContext * ctx,const char ** _ptr,const char * end)1403 parse_return_type (VerifyContext *ctx, const char **_ptr, const char *end)
1404 {
1405 const char *ptr;
1406 unsigned type = 0;
1407
1408 if (!parse_custom_mods (ctx, _ptr, end))
1409 return FALSE;
1410
1411 ptr = *_ptr;
1412 if (!safe_read8 (type, ptr, end))
1413 FAIL (ctx, g_strdup ("ReturnType: Not enough room for the type"));
1414
1415 if (type == MONO_TYPE_VOID || type == MONO_TYPE_TYPEDBYREF) {
1416 *_ptr = ptr;
1417 return TRUE;
1418 }
1419
1420 //it's a byref, update the cursor ptr
1421 if (type == MONO_TYPE_BYREF)
1422 *_ptr = ptr;
1423
1424 return parse_type (ctx, _ptr, end);
1425 }
1426
1427 static gboolean
parse_param(VerifyContext * ctx,const char ** _ptr,const char * end)1428 parse_param (VerifyContext *ctx, const char **_ptr, const char *end)
1429 {
1430 const char *ptr;
1431 unsigned type = 0;
1432
1433 if (!parse_custom_mods (ctx, _ptr, end))
1434 return FALSE;
1435
1436 ptr = *_ptr;
1437 if (!safe_read8 (type, ptr, end))
1438 FAIL (ctx, g_strdup ("Param: Not enough room for the type"));
1439
1440 if (type == MONO_TYPE_TYPEDBYREF) {
1441 *_ptr = ptr;
1442 return TRUE;
1443 }
1444
1445 //it's a byref, update the cursor ptr
1446 if (type == MONO_TYPE_BYREF) {
1447 *_ptr = ptr;
1448 if (!parse_custom_mods (ctx, _ptr, end))
1449 return FALSE;
1450 }
1451
1452 return parse_type (ctx, _ptr, end);
1453 }
1454
1455 static gboolean
parse_method_signature(VerifyContext * ctx,const char ** _ptr,const char * end,gboolean allow_sentinel,gboolean allow_unmanaged)1456 parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged)
1457 {
1458 unsigned cconv = 0;
1459 unsigned param_count = 0, gparam_count = 0, type = 0, i;
1460 const char *ptr = *_ptr;
1461 gboolean saw_sentinel = FALSE;
1462
1463 if (!safe_read8 (cconv, ptr, end))
1464 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the call conv"));
1465
1466 if (cconv & 0x80)
1467 FAIL (ctx, g_strdup ("MethodSig: CallConv has 0x80 set"));
1468
1469 if (allow_unmanaged) {
1470 if ((cconv & 0x0F) > MONO_CALL_VARARG)
1471 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not valid, it's %x", cconv & 0x0F));
1472 } else if ((cconv & 0x0F) != MONO_CALL_DEFAULT && (cconv & 0x0F) != MONO_CALL_VARARG)
1473 FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not Default or Vararg, it's %x", cconv & 0x0F));
1474
1475 if ((cconv & 0x10) && !safe_read_cint (gparam_count, ptr, end))
1476 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the generic param count"));
1477
1478 if ((cconv & 0x10) && gparam_count == 0)
1479 FAIL (ctx, g_strdup ("MethodSig: Signature with generics but zero arity"));
1480
1481 if (allow_unmanaged && (cconv & 0x10))
1482 FAIL (ctx, g_strdup ("MethodSig: Standalone signature with generic params"));
1483
1484 if (!safe_read_cint (param_count, ptr, end))
1485 FAIL (ctx, g_strdup ("MethodSig: Not enough room for the param count"));
1486
1487 if (!parse_return_type (ctx, &ptr, end))
1488 FAIL (ctx, g_strdup ("MethodSig: Error parsing return type"));
1489
1490 for (i = 0; i < param_count; ++i) {
1491 if (allow_sentinel) {
1492 if (!safe_read8 (type, ptr, end))
1493 FAIL (ctx, g_strdup_printf ("MethodSig: Not enough room for param %d type", i));
1494
1495 if (type == MONO_TYPE_SENTINEL) {
1496 if ((cconv & 0x0F) != MONO_CALL_VARARG)
1497 FAIL (ctx, g_strdup ("MethodSig: Found sentinel but signature is not vararg"));
1498
1499 if (saw_sentinel)
1500 FAIL (ctx, g_strdup ("MethodSig: More than one sentinel type"));
1501
1502 saw_sentinel = TRUE;
1503 } else {
1504 --ptr;
1505 }
1506 }
1507
1508 if (!parse_param (ctx, &ptr, end))
1509 FAIL (ctx, g_strdup_printf ("MethodSig: Error parsing arg %d", i));
1510 }
1511
1512 *_ptr = ptr;
1513 return TRUE;
1514 }
1515
1516 static gboolean
parse_property_signature(VerifyContext * ctx,const char ** _ptr,const char * end)1517 parse_property_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1518 {
1519 unsigned type = 0;
1520 unsigned sig = 0;
1521 unsigned param_count = 0, i;
1522 const char *ptr = *_ptr;
1523
1524 if (!safe_read8 (sig, ptr, end))
1525 FAIL (ctx, g_strdup ("PropertySig: Not enough room for signature"));
1526
1527 if (sig != 0x08 && sig != 0x28)
1528 FAIL (ctx, g_strdup_printf ("PropertySig: Signature is not 0x28 or 0x08: %x", sig));
1529
1530 if (!safe_read_cint (param_count, ptr, end))
1531 FAIL (ctx, g_strdup ("PropertySig: Not enough room for the param count"));
1532
1533 if (!parse_custom_mods (ctx, &ptr, end))
1534 return FALSE;
1535
1536 if (!safe_read8 (type, ptr, end))
1537 FAIL (ctx, g_strdup ("PropertySig: Not enough room for the type"));
1538
1539 //check if it's a byref. safe_read8 did update ptr, so we rollback if it's not a byref
1540 if (type != MONO_TYPE_BYREF)
1541 --ptr;
1542
1543 if (!parse_type (ctx, &ptr, end))
1544 FAIL (ctx, g_strdup ("PropertySig: Could not parse property type"));
1545
1546 for (i = 0; i < param_count; ++i) {
1547 if (!parse_custom_mods (ctx, &ptr, end))
1548 FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
1549 if (!parse_type (ctx, &ptr, end))
1550 FAIL (ctx, g_strdup_printf ("PropertySig: Error parsing arg %d", i));
1551 }
1552
1553 *_ptr = ptr;
1554 return TRUE;
1555 }
1556
1557 static gboolean
parse_field(VerifyContext * ctx,const char ** _ptr,const char * end)1558 parse_field (VerifyContext *ctx, const char **_ptr, const char *end)
1559 {
1560 const char *ptr = *_ptr;
1561 unsigned signature = 0;
1562
1563 if (!safe_read8 (signature, ptr, end))
1564 FAIL (ctx, g_strdup ("Field: Not enough room for field signature"));
1565
1566 if (signature != 0x06)
1567 FAIL (ctx, g_strdup_printf ("Field: Invalid signature 0x%x, must be 6", signature));
1568
1569 if (!parse_custom_mods (ctx, &ptr, end))
1570 return FALSE;
1571
1572 if (safe_read8 (signature, ptr, end)) {
1573 if (signature != MONO_TYPE_BYREF)
1574 --ptr;
1575 }
1576 *_ptr = ptr;
1577
1578 return parse_type (ctx, _ptr, end);
1579 }
1580
1581 static gboolean
parse_locals_signature(VerifyContext * ctx,const char ** _ptr,const char * end)1582 parse_locals_signature (VerifyContext *ctx, const char **_ptr, const char *end)
1583 {
1584 unsigned sig = 0;
1585 unsigned locals_count = 0, i;
1586 const char *ptr = *_ptr;
1587
1588 if (!safe_read8 (sig, ptr, end))
1589 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for signature"));
1590
1591 if (sig != 0x07)
1592 FAIL (ctx, g_strdup_printf ("LocalsSig: Signature is not 0x28 or 0x08: %x", sig));
1593
1594 if (!safe_read_cint (locals_count, ptr, end))
1595 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for the param count"));
1596
1597 /* LAMEIMPL: MS sometimes generates empty local signatures and its verifier is ok with.
1598 if (locals_count == 0)
1599 FAIL (ctx, g_strdup ("LocalsSig: Signature with zero locals"));
1600 */
1601
1602 for (i = 0; i < locals_count; ++i) {
1603 if (!safe_read8 (sig, ptr, end))
1604 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1605
1606 while (sig == MONO_TYPE_CMOD_REQD || sig == MONO_TYPE_CMOD_OPT || sig == MONO_TYPE_PINNED) {
1607 if (sig != MONO_TYPE_PINNED && !parse_custom_mods (ctx, &ptr, end))
1608 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1609 if (!safe_read8 (sig, ptr, end))
1610 FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
1611 }
1612
1613 if (sig == MONO_TYPE_BYREF) {
1614 if (!safe_read8 (sig, ptr, end))
1615 FAIL (ctx, g_strdup_printf ("Type: Not enough room for byref type for local %d", i));
1616 if (sig == MONO_TYPE_TYPEDBYREF)
1617 FAIL (ctx, g_strdup_printf ("Type: Invalid type typedref& for local %d", i));
1618 }
1619
1620 if (sig == MONO_TYPE_TYPEDBYREF)
1621 continue;
1622
1623 --ptr;
1624
1625 if (!parse_type (ctx, &ptr, end))
1626 FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
1627 }
1628
1629 *_ptr = ptr;
1630 return TRUE;
1631 }
1632
1633 static gboolean
is_valid_field_signature(VerifyContext * ctx,guint32 offset)1634 is_valid_field_signature (VerifyContext *ctx, guint32 offset)
1635 {
1636 guint32 size = 0;
1637 unsigned signature = 0;
1638 const char *ptr = NULL, *end;
1639
1640 if (!decode_signature_header (ctx, offset, &size, &ptr))
1641 FAIL (ctx, g_strdup ("FieldSig: Could not decode signature header"));
1642 end = ptr + size;
1643
1644 if (!safe_read8 (signature, ptr, end))
1645 FAIL (ctx, g_strdup ("FieldSig: Not enough room for the signature"));
1646
1647 if (signature != 6)
1648 FAIL (ctx, g_strdup_printf ("FieldSig: Invalid signature %x", signature));
1649 --ptr;
1650
1651 return parse_field (ctx, &ptr, end);
1652 }
1653
1654 static gboolean
is_valid_method_signature(VerifyContext * ctx,guint32 offset)1655 is_valid_method_signature (VerifyContext *ctx, guint32 offset)
1656 {
1657 guint32 size = 0;
1658 const char *ptr = NULL, *end;
1659
1660 if (!decode_signature_header (ctx, offset, &size, &ptr))
1661 FAIL (ctx, g_strdup ("MethodSig: Could not decode signature header"));
1662 end = ptr + size;
1663
1664 return parse_method_signature (ctx, &ptr, end, FALSE, FALSE);
1665 }
1666
1667 static gboolean
is_valid_memberref_method_signature(VerifyContext * ctx,guint32 offset)1668 is_valid_memberref_method_signature (VerifyContext *ctx, guint32 offset)
1669 {
1670 guint32 size = 0;
1671 const char *ptr = NULL, *end;
1672
1673 if (!decode_signature_header (ctx, offset, &size, &ptr))
1674 FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
1675 end = ptr + size;
1676
1677 return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1678 }
1679
1680
1681 static gboolean
is_valid_method_or_field_signature(VerifyContext * ctx,guint32 offset)1682 is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
1683 {
1684 guint32 size = 0;
1685 unsigned signature = 0;
1686 const char *ptr = NULL, *end;
1687
1688 if (!decode_signature_header (ctx, offset, &size, &ptr))
1689 FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
1690 end = ptr + size;
1691
1692 if (!safe_read8 (signature, ptr, end))
1693 FAIL (ctx, g_strdup ("MemberRefSig: Not enough room for the call conv"));
1694 --ptr;
1695
1696 if (signature == 0x06)
1697 return parse_field (ctx, &ptr, end);
1698
1699 return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
1700 }
1701
1702 static gboolean
is_valid_cattr_blob(VerifyContext * ctx,guint32 offset)1703 is_valid_cattr_blob (VerifyContext *ctx, guint32 offset)
1704 {
1705 guint32 size = 0;
1706 unsigned prolog = 0;
1707 const char *ptr = NULL, *end;
1708
1709 if (!offset)
1710 return TRUE;
1711
1712 if (!decode_signature_header (ctx, offset, &size, &ptr))
1713 FAIL (ctx, g_strdup ("CustomAttribute: Could not decode signature header"));
1714 end = ptr + size;
1715
1716 if (!safe_read16 (prolog, ptr, end))
1717 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1718
1719 if (prolog != 1)
1720 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1721
1722 return TRUE;
1723 }
1724
1725 static gboolean
is_valid_cattr_type(MonoType * type)1726 is_valid_cattr_type (MonoType *type)
1727 {
1728 MonoClass *klass;
1729
1730 if (type->type == MONO_TYPE_OBJECT || (type->type >= MONO_TYPE_BOOLEAN && type->type <= MONO_TYPE_STRING))
1731 return TRUE;
1732
1733 if (type->type == MONO_TYPE_VALUETYPE) {
1734 klass = mono_class_from_mono_type (type);
1735 return klass && klass->enumtype;
1736 }
1737
1738 if (type->type == MONO_TYPE_CLASS)
1739 return mono_class_from_mono_type (type) == mono_defaults.systemtype_class;
1740
1741 return FALSE;
1742 }
1743
1744 static gboolean
is_valid_ser_string_full(VerifyContext * ctx,const char ** str_start,guint32 * str_len,const char ** _ptr,const char * end)1745 is_valid_ser_string_full (VerifyContext *ctx, const char **str_start, guint32 *str_len, const char **_ptr, const char *end)
1746 {
1747 guint32 size = 0;
1748 const char *ptr = *_ptr;
1749
1750 *str_start = NULL;
1751 *str_len = 0;
1752
1753 if (ptr >= end)
1754 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string size"));
1755
1756 /*NULL string*/
1757 if (*ptr == (char)0xFF) {
1758 *_ptr = ptr + 1;
1759 return TRUE;
1760 }
1761
1762 if (!safe_read_cint (size, ptr, end))
1763 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string size"));
1764
1765 if (ADDP_IS_GREATER_OR_OVF (ptr, size, end))
1766 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string"));
1767
1768 *str_start = ptr;
1769 *str_len = size;
1770
1771 *_ptr = ptr + size;
1772 return TRUE;
1773 }
1774
1775 static gboolean
is_valid_ser_string(VerifyContext * ctx,const char ** _ptr,const char * end)1776 is_valid_ser_string (VerifyContext *ctx, const char **_ptr, const char *end)
1777 {
1778 const char *dummy_str;
1779 guint32 dummy_int;
1780 return is_valid_ser_string_full (ctx, &dummy_str, &dummy_int, _ptr, end);
1781 }
1782
1783 static MonoClass*
get_enum_by_encoded_name(VerifyContext * ctx,const char ** _ptr,const char * end)1784 get_enum_by_encoded_name (VerifyContext *ctx, const char **_ptr, const char *end)
1785 {
1786 MonoError error;
1787 MonoType *type;
1788 MonoClass *klass;
1789 const char *str_start = NULL;
1790 const char *ptr = *_ptr;
1791 char *enum_name;
1792 guint32 str_len = 0;
1793
1794 if (!is_valid_ser_string_full (ctx, &str_start, &str_len, &ptr, end))
1795 return NULL;
1796
1797 /*NULL or empty string*/
1798 if (str_start == NULL || str_len == 0) {
1799 ADD_ERROR_NO_RETURN (ctx, g_strdup ("CustomAttribute: Null or empty enum name"));
1800 return NULL;
1801 }
1802
1803 enum_name = (char *)g_memdup (str_start, str_len + 1);
1804 enum_name [str_len] = 0;
1805 type = mono_reflection_type_from_name_checked (enum_name, ctx->image, &error);
1806 if (!type || !is_ok (&error)) {
1807 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute: Invalid enum class %s, due to %s", enum_name, mono_error_get_message (&error)));
1808 g_free (enum_name);
1809 mono_error_cleanup (&error);
1810 return NULL;
1811 }
1812 g_free (enum_name);
1813
1814 klass = mono_class_from_mono_type (type);
1815 if (!klass || !klass->enumtype) {
1816 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute:Class %s::%s is not an enum", klass->name_space, klass->name));
1817 return NULL;
1818 }
1819
1820 *_ptr = ptr;
1821 return klass;
1822 }
1823
1824 static gboolean
is_valid_fixed_param(VerifyContext * ctx,MonoType * mono_type,const char ** _ptr,const char * end)1825 is_valid_fixed_param (VerifyContext *ctx, MonoType *mono_type, const char **_ptr, const char *end)
1826 {
1827 MonoClass *klass;
1828 const char *ptr = *_ptr;
1829 int elem_size = 0;
1830 guint32 element_count, i;
1831 int type;
1832
1833 klass = mono_type->data.klass;
1834 type = mono_type->type;
1835
1836 handle_enum:
1837 switch (type) {
1838 case MONO_TYPE_BOOLEAN:
1839 case MONO_TYPE_I1:
1840 case MONO_TYPE_U1:
1841 elem_size = 1;
1842 break;
1843 case MONO_TYPE_I2:
1844 case MONO_TYPE_U2:
1845 case MONO_TYPE_CHAR:
1846 elem_size = 2;
1847 break;
1848 case MONO_TYPE_I4:
1849 case MONO_TYPE_U4:
1850 case MONO_TYPE_R4:
1851 elem_size = 4;
1852 break;
1853 case MONO_TYPE_I8:
1854 case MONO_TYPE_U8:
1855 case MONO_TYPE_R8:
1856 elem_size = 8;
1857 break;
1858
1859 case MONO_TYPE_STRING:
1860 *_ptr = ptr;
1861 return is_valid_ser_string (ctx, _ptr, end);
1862
1863 case MONO_TYPE_OBJECT: {
1864 unsigned sub_type = 0;
1865 if (!safe_read8 (sub_type, ptr, end))
1866 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array type"));
1867
1868 if (sub_type >= MONO_TYPE_BOOLEAN && sub_type <= MONO_TYPE_STRING) {
1869 type = sub_type;
1870 goto handle_enum;
1871 }
1872 if (sub_type == MONO_TYPE_ENUM) {
1873 klass = get_enum_by_encoded_name (ctx, &ptr, end);
1874 if (!klass)
1875 return FALSE;
1876
1877 klass = klass->element_class;
1878 type = klass->byval_arg.type;
1879 goto handle_enum;
1880 }
1881 if (sub_type == 0x50) { /*Type*/
1882 *_ptr = ptr;
1883 return is_valid_ser_string (ctx, _ptr, end);
1884 }
1885 if (sub_type == MONO_TYPE_SZARRAY) {
1886 MonoType simple_type = {{0}};
1887 unsigned etype = 0;
1888 if (!safe_read8 (etype, ptr, end))
1889 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array element type"));
1890
1891 if (etype == MONO_TYPE_ENUM) {
1892 klass = get_enum_by_encoded_name (ctx, &ptr, end);
1893 if (!klass)
1894 return FALSE;
1895 } else if (etype == 0x50 || etype == MONO_TYPE_CLASS) {
1896 klass = mono_defaults.systemtype_class;
1897 } else if ((etype >= MONO_TYPE_BOOLEAN && etype <= MONO_TYPE_STRING) || etype == 0x51) {
1898 simple_type.type = etype == 0x51 ? MONO_TYPE_OBJECT : (MonoTypeEnum)etype;
1899 klass = mono_class_from_mono_type (&simple_type);
1900 } else
1901 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype));
1902
1903 type = MONO_TYPE_SZARRAY;
1904 goto handle_enum;
1905 }
1906 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid boxed object type %x", sub_type));
1907 }
1908
1909 case MONO_TYPE_CLASS:
1910 if (klass && klass->enumtype) {
1911 klass = klass->element_class;
1912 type = klass->byval_arg.type;
1913 goto handle_enum;
1914 }
1915
1916 if (klass != mono_defaults.systemtype_class)
1917 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid class parameter type %s:%s ",klass->name_space, klass->name));
1918 *_ptr = ptr;
1919 return is_valid_ser_string (ctx, _ptr, end);
1920
1921 case MONO_TYPE_VALUETYPE:
1922 if (!klass || !klass->enumtype)
1923 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid valuetype parameter expected enum %s:%s ",klass->name_space, klass->name));
1924
1925 klass = klass->element_class;
1926 type = klass->byval_arg.type;
1927 goto handle_enum;
1928
1929 case MONO_TYPE_SZARRAY:
1930 mono_type = &klass->byval_arg;
1931 if (!is_valid_cattr_type (mono_type))
1932 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %s:%s ",klass->name_space, klass->name));
1933 if (!safe_read32 (element_count, ptr, end))
1934 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid class parameter type %s:%s ",klass->name_space, klass->name));
1935 if (element_count == 0xFFFFFFFFu) {
1936 *_ptr = ptr;
1937 return TRUE;
1938 }
1939 for (i = 0; i < element_count; ++i) {
1940 if (!is_valid_fixed_param (ctx, mono_type, &ptr, end))
1941 return FALSE;
1942 }
1943 *_ptr = ptr;
1944 return TRUE;
1945 default:
1946 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid parameter type %x ", type));
1947 }
1948
1949 if (ADDP_IS_GREATER_OR_OVF (ptr, elem_size, end))
1950 FAIL (ctx, g_strdup ("CustomAttribute: Not enough space for element"));
1951 *_ptr = ptr + elem_size;
1952 return TRUE;
1953 }
1954
1955 static gboolean
is_valid_cattr_content(VerifyContext * ctx,MonoMethod * ctor,const char * ptr,guint32 size)1956 is_valid_cattr_content (VerifyContext *ctx, MonoMethod *ctor, const char *ptr, guint32 size)
1957 {
1958 MonoError error;
1959 unsigned prolog = 0;
1960 const char *end;
1961 MonoMethodSignature *sig;
1962 int args, i;
1963 unsigned num_named;
1964
1965 if (!ctor)
1966 FAIL (ctx, g_strdup ("CustomAttribute: Invalid constructor"));
1967
1968 sig = mono_method_signature_checked (ctor, &error);
1969 if (!mono_error_ok (&error)) {
1970 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute: Invalid constructor signature %s", mono_error_get_message (&error)));
1971 mono_error_cleanup (&error);
1972 return FALSE;
1973 }
1974
1975 if (sig->sentinelpos != -1 || sig->call_convention == MONO_CALL_VARARG)
1976 FAIL (ctx, g_strdup ("CustomAttribute: Constructor cannot have VARAG signature"));
1977
1978 end = ptr + size;
1979
1980 if (!safe_read16 (prolog, ptr, end))
1981 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
1982
1983 if (prolog != 1)
1984 FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
1985
1986 args = sig->param_count;
1987 for (i = 0; i < args; ++i) {
1988 MonoType *arg_type = sig->params [i];
1989 if (!is_valid_fixed_param (ctx, arg_type, &ptr, end))
1990 return FALSE;
1991 }
1992
1993 if (!safe_read16 (num_named, ptr, end))
1994 FAIL (ctx, g_strdup ("CustomAttribute: Not enough space for num_named field"));
1995
1996 for (i = 0; i < num_named; ++i) {
1997 MonoType *type, simple_type = {{0}};
1998 unsigned kind;
1999
2000 if (!safe_read8 (kind, ptr, end))
2001 FAIL (ctx, g_strdup_printf ("CustomAttribute: Not enough space for named parameter %d kind", i));
2002 if (kind != 0x53 && kind != 0x54)
2003 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid named parameter %d kind %x", i, kind));
2004 if (!safe_read8 (kind, ptr, end))
2005 FAIL (ctx, g_strdup_printf ("CustomAttribute: Not enough space for named parameter %d type", i));
2006
2007 if (kind >= MONO_TYPE_BOOLEAN && kind <= MONO_TYPE_STRING) {
2008 simple_type.type = (MonoTypeEnum)kind;
2009 type = &simple_type;
2010 } else if (kind == MONO_TYPE_ENUM) {
2011 MonoClass *klass = get_enum_by_encoded_name (ctx, &ptr, end);
2012 if (!klass)
2013 return FALSE;
2014 type = &klass->byval_arg;
2015 } else if (kind == 0x50) {
2016 type = &mono_defaults.systemtype_class->byval_arg;
2017 } else if (kind == 0x51) {
2018 type = &mono_defaults.object_class->byval_arg;
2019 } else if (kind == MONO_TYPE_SZARRAY) {
2020 MonoClass *klass;
2021 unsigned etype = 0;
2022 if (!safe_read8 (etype, ptr, end))
2023 FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array element type"));
2024
2025 if (etype == MONO_TYPE_ENUM) {
2026 klass = get_enum_by_encoded_name (ctx, &ptr, end);
2027 if (!klass)
2028 return FALSE;
2029 } else if (etype == 0x50 || etype == MONO_TYPE_CLASS) {
2030 klass = mono_defaults.systemtype_class;
2031 } else if ((etype >= MONO_TYPE_BOOLEAN && etype <= MONO_TYPE_STRING) || etype == 0x51) {
2032 simple_type.type = etype == 0x51 ? MONO_TYPE_OBJECT : (MonoTypeEnum)etype;
2033 klass = mono_class_from_mono_type (&simple_type);
2034 } else
2035 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype));
2036
2037 type = &mono_array_class_get (klass, 1)->byval_arg;
2038 } else {
2039 FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid named parameter type %x", kind));
2040 }
2041
2042 if (!is_valid_ser_string (ctx, &ptr, end))
2043 return FALSE;
2044
2045 if (!is_valid_fixed_param (ctx, type, &ptr, end))
2046 return FALSE;
2047
2048 }
2049
2050 return TRUE;
2051 }
2052
2053 static gboolean
is_valid_marshal_spec(VerifyContext * ctx,guint32 offset)2054 is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
2055 {
2056 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2057 //TODO do proper verification
2058 return blob.size >= 1 && blob.size - 1 >= offset;
2059 }
2060
2061 static gboolean
is_valid_permission_set(VerifyContext * ctx,guint32 offset)2062 is_valid_permission_set (VerifyContext *ctx, guint32 offset)
2063 {
2064 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2065 //TODO do proper verification
2066 return blob.size >= 1 && blob.size - 1 >= offset;
2067 }
2068
2069 static gboolean
is_valid_standalonesig_blob(VerifyContext * ctx,guint32 offset)2070 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
2071 {
2072 guint32 size = 0;
2073 unsigned signature = 0;
2074 const char *ptr = NULL, *end;
2075
2076 if (!decode_signature_header (ctx, offset, &size, &ptr))
2077 FAIL (ctx, g_strdup ("StandAloneSig: Could not decode signature header"));
2078 end = ptr + size;
2079
2080 if (!safe_read8 (signature, ptr, end))
2081 FAIL (ctx, g_strdup ("StandAloneSig: Not enough room for the call conv"));
2082
2083 --ptr;
2084 if (signature == 0x07)
2085 return parse_locals_signature (ctx, &ptr, end);
2086
2087 /*F# and managed C++ produce standalonesig for fields even thou the spec doesn't mention it.*/
2088 if (signature == 0x06)
2089 return parse_field (ctx, &ptr, end);
2090
2091 return parse_method_signature (ctx, &ptr, end, TRUE, TRUE);
2092 }
2093
2094 static gboolean
is_valid_property_sig_blob(VerifyContext * ctx,guint32 offset)2095 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
2096 {
2097 guint32 size = 0;
2098 const char *ptr = NULL, *end;
2099
2100 if (!decode_signature_header (ctx, offset, &size, &ptr))
2101 FAIL (ctx, g_strdup ("PropertySig: Could not decode signature header"));
2102 end = ptr + size;
2103
2104 return parse_property_signature (ctx, &ptr, end);
2105 }
2106
2107 static gboolean
is_valid_typespec_blob(VerifyContext * ctx,guint32 offset)2108 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
2109 {
2110 guint32 size = 0;
2111 const char *ptr = NULL, *end;
2112 unsigned type = 0;
2113
2114 if (!decode_signature_header (ctx, offset, &size, &ptr))
2115 FAIL (ctx, g_strdup ("TypeSpec: Could not decode signature header"));
2116 end = ptr + size;
2117
2118 if (!parse_custom_mods (ctx, &ptr, end))
2119 return FALSE;
2120
2121 if (!safe_read8 (type, ptr, end))
2122 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for type"));
2123
2124 if (type == MONO_TYPE_BYREF) {
2125 if (!safe_read8 (type, ptr, end))
2126 FAIL (ctx, g_strdup ("TypeSpec: Not enough room for byref type"));
2127 if (type == MONO_TYPE_TYPEDBYREF)
2128 FAIL (ctx, g_strdup ("TypeSpec: Invalid type typedref&"));
2129 }
2130
2131 if (type == MONO_TYPE_TYPEDBYREF)
2132 return TRUE;
2133
2134 --ptr;
2135 return parse_type (ctx, &ptr, end);
2136 }
2137
2138 static gboolean
is_valid_methodspec_blob(VerifyContext * ctx,guint32 offset)2139 is_valid_methodspec_blob (VerifyContext *ctx, guint32 offset)
2140 {
2141 guint32 size = 0;
2142 const char *ptr = NULL, *end;
2143 unsigned type = 0;
2144 unsigned count = 0, i;
2145
2146 if (!decode_signature_header (ctx, offset, &size, &ptr))
2147 FAIL (ctx, g_strdup ("MethodSpec: Could not decode signature header"));
2148 end = ptr + size;
2149
2150 if (!safe_read8 (type, ptr, end))
2151 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for call convention"));
2152
2153 if (type != 0x0A)
2154 FAIL (ctx, g_strdup_printf ("MethodSpec: Invalid call convention 0x%x, expected 0x0A", type));
2155
2156 if (!safe_read_cint (count, ptr, end))
2157 FAIL (ctx, g_strdup ("MethodSpec: Not enough room for parameter count"));
2158
2159 if (!count)
2160 FAIL (ctx, g_strdup ("MethodSpec: Zero generic argument count"));
2161
2162 for (i = 0; i < count; ++i) {
2163 if (!parse_custom_mods (ctx, &ptr, end))
2164 return FALSE;
2165 if (!parse_type (ctx, &ptr, end))
2166 FAIL (ctx, g_strdup_printf ("MethodSpec: Could not parse parameter %d", i + 1));
2167 }
2168 return TRUE;
2169 }
2170
2171 static gboolean
is_valid_blob_object(VerifyContext * ctx,guint32 offset,guint32 minsize)2172 is_valid_blob_object (VerifyContext *ctx, guint32 offset, guint32 minsize)
2173 {
2174 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2175 guint32 entry_size, bytes;
2176
2177 if (blob.size < offset)
2178 return FALSE;
2179
2180 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
2181 return FALSE;
2182
2183 if (entry_size < minsize)
2184 return FALSE;
2185
2186 if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
2187 return FALSE;
2188 entry_size += bytes;
2189
2190 return !ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size);
2191 }
2192
2193 static gboolean
is_valid_constant(VerifyContext * ctx,guint32 type,guint32 offset)2194 is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
2195 {
2196 OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
2197 guint32 size, entry_size, bytes;
2198
2199 if (blob.size < offset)
2200 FAIL (ctx, g_strdup ("ContantValue: invalid offset"));
2201
2202 if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
2203 FAIL (ctx, g_strdup ("ContantValue: not enough space to decode size"));
2204
2205 if (type == MONO_TYPE_STRING) {
2206 //String is encoded as: compressed_int:len len *bytes
2207 offset += bytes;
2208
2209 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size))
2210 FAIL (ctx, g_strdup_printf ("ContantValue: not enough space for string, required %d but got %d", entry_size * 2, blob.size - offset));
2211
2212 return TRUE;
2213 }
2214
2215 switch (type) {
2216 case MONO_TYPE_BOOLEAN:
2217 case MONO_TYPE_I1:
2218 case MONO_TYPE_U1:
2219 size = 1;
2220 break;
2221 case MONO_TYPE_CHAR:
2222 case MONO_TYPE_I2:
2223 case MONO_TYPE_U2:
2224 size = 2;
2225 break;
2226 case MONO_TYPE_I4:
2227 case MONO_TYPE_U4:
2228 case MONO_TYPE_R4:
2229 case MONO_TYPE_CLASS:
2230 size = 4;
2231 break;
2232
2233 case MONO_TYPE_I8:
2234 case MONO_TYPE_U8:
2235 case MONO_TYPE_R8:
2236 size = 8;
2237 break;
2238 default:
2239 g_assert_not_reached ();
2240 }
2241
2242 if (size != entry_size)
2243 FAIL (ctx, g_strdup_printf ("ContantValue: Expected size %d but got %d", size, entry_size));
2244
2245 offset += bytes;
2246
2247 if (ADD_IS_GREATER_OR_OVF (offset, size, blob.size))
2248 FAIL (ctx, g_strdup_printf ("ContantValue: Not enough room for constant, required %d but have %d", size, blob.size - offset));
2249
2250 if (type == MONO_TYPE_CLASS && read32 (ctx->data + blob.offset + offset))
2251 FAIL (ctx, g_strdup_printf ("ContantValue: Type is class but value is not null"));
2252 return TRUE;
2253 }
2254
2255 #define FAT_HEADER_INVALID_FLAGS ~(0x3 | 0x8 | 0x10 | 0xF000)
2256 //only 0x01, 0x40 and 0x80 are allowed
2257 #define SECTION_HEADER_INVALID_FLAGS 0x3E
2258
2259 static gboolean
is_valid_method_header(VerifyContext * ctx,guint32 rva,guint32 * locals_token)2260 is_valid_method_header (VerifyContext *ctx, guint32 rva, guint32 *locals_token)
2261 {
2262 unsigned local_vars_tok, code_size, offset = mono_cli_rva_image_map (ctx->image, rva);
2263 unsigned header = 0;
2264 unsigned fat_header = 0, size = 0, max_stack;
2265 const char *ptr = NULL, *end;
2266
2267 *locals_token = 0;
2268
2269 if (offset == INVALID_ADDRESS)
2270 FAIL (ctx, g_strdup ("MethodHeader: Invalid RVA"));
2271
2272 ptr = ctx->data + offset;
2273 end = ctx->data + ctx->size; /*no worries if it spawns multiple sections*/
2274
2275 if (!safe_read8 (header, ptr, end))
2276 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for header"));
2277
2278 switch (header & 0x3) {
2279 case 0:
2280 case 1:
2281 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid header type 0x%x", header & 0x3));
2282 case 2:
2283 header >>= 2;
2284 if (ADDP_IS_GREATER_OR_OVF (ptr, header, end))
2285 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for method body. Required %d, but only %d is available", header, (int)(end - ptr)));
2286 return TRUE;
2287 }
2288 //FAT HEADER
2289 --ptr;
2290 if (!safe_read16 (fat_header, ptr, end))
2291 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for fat header"));
2292
2293 size = (fat_header >> 12) & 0xF;
2294 if (size != 3)
2295 FAIL (ctx, g_strdup ("MethodHeader: header size must be 3"));
2296
2297 if (!safe_read16 (max_stack, ptr, end))
2298 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for max stack"));
2299
2300 if (!safe_read32 (code_size, ptr, end))
2301 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for code size"));
2302
2303 if (!safe_read32 (local_vars_tok, ptr, end))
2304 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for local vars tok"));
2305
2306 if (local_vars_tok) {
2307 if (((local_vars_tok >> 24) & 0xFF) != 0x11)
2308 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature table 0x%x", ((local_vars_tok >> 24) & 0xFF)));
2309 if ((local_vars_tok & 0xFFFFFF) > ctx->image->tables [MONO_TABLE_STANDALONESIG].rows)
2310 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature points to invalid row 0x%x", local_vars_tok & 0xFFFFFF));
2311 if (!(local_vars_tok & 0xFFFFFF))
2312 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature with zero index"));
2313 *locals_token = local_vars_tok & 0xFFFFFF;
2314 }
2315
2316 if (fat_header & FAT_HEADER_INVALID_FLAGS)
2317 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid fat signature flags %x", fat_header & FAT_HEADER_INVALID_FLAGS));
2318
2319 if (ADDP_IS_GREATER_OR_OVF (ptr, code_size, end))
2320 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for code %d", code_size));
2321
2322 if (!(fat_header & 0x08))
2323 return TRUE;
2324
2325 ptr += code_size;
2326
2327 do {
2328 unsigned section_header = 0, section_size = 0;
2329 gboolean is_fat;
2330
2331 ptr = dword_align (ptr);
2332 if (!safe_read32 (section_header, ptr, end))
2333 FAIL (ctx, g_strdup ("MethodHeader: Not enough room for data section header"));
2334
2335 if (section_header & SECTION_HEADER_INVALID_FLAGS)
2336 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section header flags 0x%x", section_header & SECTION_HEADER_INVALID_FLAGS));
2337
2338 is_fat = (section_header & METHOD_HEADER_SECTION_FAT_FORMAT) != 0;
2339 section_size = (section_header >> 8) & (is_fat ? 0xFFFFFF : 0xFF);
2340
2341 if (section_size < 4)
2342 FAIL (ctx, g_strdup_printf ("MethodHeader: Section size too small"));
2343
2344 if (ADDP_IS_GREATER_OR_OVF (ptr, section_size - 4, end)) /*must be section_size -4 as ptr was incremented by safe_read32*/
2345 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section content %d", section_size));
2346
2347 if (section_header & METHOD_HEADER_SECTION_EHTABLE) {
2348 guint32 i, clauses = section_size / (is_fat ? 24 : 12);
2349 /*
2350 LAMEIMPL: MS emits section_size without accounting for header size.
2351 Mono does as the spec says. section_size is header + section
2352 MS's peverify happily accepts both.
2353 */
2354 if ((clauses * (is_fat ? 24 : 12) != section_size) && (clauses * (is_fat ? 24 : 12) + 4 != section_size))
2355 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid EH section size %d, it's not of the expected size %d", section_size, clauses * (is_fat ? 24 : 12)));
2356
2357 /* only verify the class token is verified as the rest is done by the IL verifier*/
2358 for (i = 0; i < clauses; ++i) {
2359 unsigned flags = *(unsigned char*)ptr;
2360 unsigned class_token = 0;
2361 ptr += (is_fat ? 20 : 8);
2362 if (!safe_read32 (class_token, ptr, end))
2363 FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section %d", i));
2364 if (flags == MONO_EXCEPTION_CLAUSE_NONE && class_token) {
2365 guint table = mono_metadata_token_table (class_token);
2366 if (table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPESPEC)
2367 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token table %x", i, table));
2368 if (mono_metadata_token_index (class_token) > ctx->image->tables [table].rows)
2369 FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token index %x", i, mono_metadata_token_index (class_token)));
2370 }
2371 }
2372 }
2373
2374 if (!(section_header & METHOD_HEADER_SECTION_MORE_SECTS))
2375 break;
2376 } while (1);
2377 return TRUE;
2378 }
2379
2380 static void
verify_module_table(VerifyContext * ctx)2381 verify_module_table (VerifyContext *ctx)
2382 {
2383 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
2384 guint32 data [MONO_MODULE_SIZE];
2385
2386 if (table->rows != 1)
2387 ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
2388
2389 mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
2390
2391 if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
2392 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
2393
2394 if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
2395 ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
2396
2397 if (data [MONO_MODULE_ENC] != 0)
2398 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
2399
2400 if (data [MONO_MODULE_ENCBASE] != 0)
2401 ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
2402 }
2403
2404 static void
verify_typeref_table(VerifyContext * ctx)2405 verify_typeref_table (VerifyContext *ctx)
2406 {
2407 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
2408 MonoError error;
2409 guint32 i;
2410
2411 for (i = 0; i < table->rows; ++i) {
2412 mono_verifier_verify_typeref_row (ctx->image, i, &error);
2413 add_from_mono_error (ctx, &error);
2414 }
2415 }
2416
2417 /*bits 9,11,14,15,19,21,24-31 */
2418 #define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
2419 static void
verify_typedef_table(VerifyContext * ctx)2420 verify_typedef_table (VerifyContext *ctx)
2421 {
2422 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2423 guint32 data [MONO_TYPEDEF_SIZE];
2424 guint32 fieldlist = 1, methodlist = 1, visibility;
2425 int i;
2426
2427 if (table->rows == 0)
2428 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2429
2430 for (i = 0; i < table->rows; ++i) {
2431 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2432 if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
2433 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x rejected bits: 0x%08x", i, data [MONO_TYPEDEF_FLAGS], data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS));
2434
2435 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
2436 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
2437
2438 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
2439 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2440
2441 if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
2442 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
2443
2444 if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) && (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
2445 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
2446
2447 if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
2448 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
2449
2450 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
2451 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
2452
2453 if (data [MONO_TYPEDEF_EXTENDS] && !is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
2454 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
2455
2456 if (data [MONO_TYPEDEF_EXTENDS] && !get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
2457 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d zero coded extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
2458
2459 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
2460 if ((visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) &&
2461 search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1) == -1)
2462 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d has nested visibility but no rows in the NestedClass table", i));
2463
2464 if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
2465 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
2466
2467 if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
2468 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
2469
2470 if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
2471 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));
2472
2473 if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
2474 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
2475
2476 if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
2477 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
2478
2479 if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
2480 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));
2481
2482 fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
2483 methodlist = data [MONO_TYPEDEF_METHOD_LIST];
2484 }
2485 }
2486
2487 static void
verify_typedef_table_full(VerifyContext * ctx)2488 verify_typedef_table_full (VerifyContext *ctx)
2489 {
2490 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2491 guint32 data [MONO_TYPEDEF_SIZE];
2492 int i;
2493
2494 if (table->rows == 0)
2495 ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
2496
2497 for (i = 0; i < table->rows; ++i) {
2498 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
2499
2500 if (i == 0) {
2501 /*XXX it's ok if <module> extends object, or anything at all, actually. */
2502 /*if (data [MONO_TYPEDEF_EXTENDS] != 0)
2503 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
2504 */
2505 continue;
2506 }
2507
2508 if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
2509 if (data [MONO_TYPEDEF_EXTENDS])
2510 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
2511 } else {
2512 gboolean is_sys_obj = typedef_is_system_object (ctx, data);
2513 gboolean has_parent = get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]) != 0;
2514
2515 if (is_sys_obj) {
2516 if (has_parent)
2517 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
2518 } else {
2519 if (!has_parent) {
2520 ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
2521 }
2522 }
2523 }
2524 }
2525 }
2526
2527 /*bits 3,11,14 */
2528 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
2529 static void
verify_field_table(VerifyContext * ctx)2530 verify_field_table (VerifyContext *ctx)
2531 {
2532 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2533 guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
2534 int i;
2535
2536 module_field_list = (guint32)-1;
2537 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2538 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2539 module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
2540 }
2541
2542 for (i = 0; i < table->rows; ++i) {
2543 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2544 flags = data [MONO_FIELD_FLAGS];
2545
2546 if (flags & INVALID_FIELD_FLAG_BITS)
2547 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
2548
2549 if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)
2550 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
2551
2552 if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
2553 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
2554
2555 if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
2556 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
2557
2558 if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
2559 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
2560
2561 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
2562 search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
2563 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
2564
2565 if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
2566 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2567 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2568
2569 if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
2570 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
2571 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
2572
2573 if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
2574 search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
2575 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
2576
2577 if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
2578 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
2579
2580 if (data [MONO_FIELD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_FIELD_SIGNATURE], 1))
2581 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature blob token 0x%x", i, data [MONO_FIELD_SIGNATURE]));
2582
2583 //TODO verify contant flag
2584
2585 if (i + 1 < module_field_list) {
2586 guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
2587 if (!(flags & FIELD_ATTRIBUTE_STATIC))
2588 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
2589 if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
2590 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
2591 }
2592 }
2593 }
2594
2595 static void
verify_field_table_full(VerifyContext * ctx)2596 verify_field_table_full (VerifyContext *ctx)
2597 {
2598 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
2599 guint32 data [MONO_FIELD_SIZE];
2600 int i;
2601
2602 for (i = 0; i < table->rows; ++i) {
2603 mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
2604
2605 if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
2606 ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
2607 }
2608 }
2609
2610 /*bits 8,9,10,11,13,14,15*/
2611 #define INVALID_METHOD_IMPLFLAG_BITS ((1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
2612 static void
verify_method_table(VerifyContext * ctx)2613 verify_method_table (VerifyContext *ctx)
2614 {
2615 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2616 guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
2617 guint32 paramlist = 1;
2618 gboolean is_ctor, is_cctor;
2619 const char *name;
2620 int i;
2621
2622 module_method_list = (guint32)-1;
2623 if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
2624 MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
2625 module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
2626 }
2627
2628 for (i = 0; i < table->rows; ++i) {
2629 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2630 rva = data [MONO_METHOD_RVA];
2631 implflags = data [MONO_METHOD_IMPLFLAGS];
2632 flags = data [MONO_METHOD_FLAGS];
2633 access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
2634 code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
2635
2636
2637 if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
2638 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
2639
2640 if (access == 0x7)
2641 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
2642
2643 if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
2644 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
2645
2646 name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
2647 is_ctor = !strcmp (".ctor", name);
2648 is_cctor = !strcmp (".cctor", name);
2649
2650 if ((is_ctor || is_cctor) &&
2651 search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
2652 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
2653
2654 if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
2655 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
2656
2657 if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
2658 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
2659 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
2660 if (flags & METHOD_ATTRIBUTE_FINAL)
2661 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and Final", i));
2662 if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
2663 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
2664 }
2665
2666 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
2667 ADD_WARNING (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
2668
2669 if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
2670 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
2671
2672 //XXX no checks against cas stuff 10,11,12,13)
2673
2674 //TODO check iface with .ctor (15,16)
2675
2676 if (i + 1 < module_method_list) {
2677 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2678 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
2679 if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
2680 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
2681 if (access == METHOD_ATTRIBUTE_FAMILY || access == METHOD_ATTRIBUTE_FAM_AND_ASSEM || access == METHOD_ATTRIBUTE_FAM_OR_ASSEM)
2682 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public, Private or Assembly", i));
2683 }
2684
2685 //TODO check valuetype for synchronized
2686
2687 if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
2688 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
2689
2690 if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
2691 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
2692 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
2693 if (!(flags & METHOD_ATTRIBUTE_STATIC))
2694 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but not Static", i));
2695 }
2696
2697 if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
2698 !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2699 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
2700
2701 if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
2702 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
2703
2704 //TODO check signature contents
2705
2706 if (rva) {
2707 if ((flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) || (implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
2708 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is either Abstract, InternalCall or PinvokeImpl", i));
2709 if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
2710 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
2711 } else {
2712 if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
2713 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
2714 }
2715
2716 if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
2717 if (rva)
2718 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
2719 if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
2720 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
2721 }
2722 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
2723 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
2724
2725 if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
2726 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
2727
2728 if (data [MONO_METHOD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHOD_SIGNATURE], 1))
2729 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature blob token 0x%x", i, data [MONO_METHOD_SIGNATURE]));
2730
2731 if (data [MONO_METHOD_PARAMLIST] == 0)
2732 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
2733
2734 if (data [MONO_METHOD_PARAMLIST] < paramlist)
2735 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));
2736
2737 if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
2738 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
2739
2740 paramlist = data [MONO_METHOD_PARAMLIST];
2741
2742 }
2743 }
2744
2745 static void
verify_method_table_full(VerifyContext * ctx)2746 verify_method_table_full (VerifyContext *ctx)
2747 {
2748 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2749 guint32 data [MONO_METHOD_SIZE], rva, locals_token;
2750 int i;
2751
2752 for (i = 0; i < table->rows; ++i) {
2753 mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
2754 rva = data [MONO_METHOD_RVA];
2755
2756 if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
2757 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
2758
2759 if (rva && !is_valid_method_header (ctx, rva, &locals_token))
2760 ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
2761 }
2762 }
2763
2764 static guint32
get_next_param_count(VerifyContext * ctx,guint32 * current_method)2765 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
2766 {
2767 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
2768 guint32 row = *current_method;
2769 guint32 paramlist, tmp;
2770
2771
2772 paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
2773 while (row < table->rows) {
2774 tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
2775 if (tmp > paramlist) {
2776 *current_method = row;
2777 return tmp - paramlist;
2778 }
2779 ++row;
2780 }
2781
2782 /*no more methods, all params apply to the last one*/
2783 *current_method = table->rows;
2784 return (guint32)-1;
2785 }
2786
2787
2788 #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))
2789 static void
verify_param_table(VerifyContext * ctx)2790 verify_param_table (VerifyContext *ctx)
2791 {
2792 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
2793 guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
2794 gboolean first_param = TRUE;
2795 int i;
2796
2797 if (ctx->image->tables [MONO_TABLE_METHOD].rows == 0) {
2798 if (table->rows > 0)
2799 ADD_ERROR (ctx, g_strdup ("Param table has rows while the method table has zero"));
2800 return;
2801 }
2802
2803 remaining_params = get_next_param_count (ctx, ¤t_method);
2804
2805 for (i = 0; i < table->rows; ++i) {
2806 mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
2807 flags = data [MONO_PARAM_FLAGS];
2808
2809 if (flags & INVALID_PARAM_FLAGS_BITS)
2810 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
2811
2812 if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
2813 if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
2814 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
2815 } else {
2816 if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
2817 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
2818 }
2819
2820 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)
2821 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
2822
2823 if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
2824 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
2825
2826 if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
2827 ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
2828
2829 first_param = FALSE;
2830 sequence = data [MONO_PARAM_SEQUENCE];
2831 if (--remaining_params == 0) {
2832 remaining_params = get_next_param_count (ctx, ¤t_method);
2833 first_param = TRUE;
2834 }
2835 }
2836 }
2837
2838 static void
verify_interfaceimpl_table(VerifyContext * ctx)2839 verify_interfaceimpl_table (VerifyContext *ctx)
2840 {
2841 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
2842 guint32 data [MONO_INTERFACEIMPL_SIZE];
2843 int i;
2844
2845 for (i = 0; i < table->rows; ++i) {
2846 mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
2847 if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
2848 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_INTERFACEIMPL_CLASS]));
2849
2850 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2851 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
2852
2853 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
2854 ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
2855 }
2856 }
2857
2858 static void
verify_memberref_table(VerifyContext * ctx)2859 verify_memberref_table (VerifyContext *ctx)
2860 {
2861 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2862 guint32 data [MONO_MEMBERREF_SIZE];
2863 int i;
2864
2865 for (i = 0; i < table->rows; ++i) {
2866 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2867
2868 if (!is_valid_coded_index (ctx, MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2869 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded index 0x%08x", i, data [MONO_MEMBERREF_CLASS]));
2870
2871 if (!get_coded_index_token (MEMBERREF_PARENT_DESC, data [MONO_MEMBERREF_CLASS]))
2872 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Class field coded is null", i));
2873
2874 if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
2875 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
2876
2877 if (data [MONO_MEMBERREF_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_MEMBERREF_SIGNATURE], 1))
2878 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d invalid signature blob token 0x%x", i, data [MONO_MEMBERREF_SIGNATURE]));
2879 }
2880 }
2881
2882
2883 static void
verify_memberref_table_full(VerifyContext * ctx)2884 verify_memberref_table_full (VerifyContext *ctx)
2885 {
2886 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
2887 guint32 data [MONO_MEMBERREF_SIZE];
2888 int i;
2889
2890 for (i = 0; i < table->rows; ++i) {
2891 mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
2892
2893 if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
2894 ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field 0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
2895 }
2896 }
2897
2898 static void
verify_constant_table(VerifyContext * ctx)2899 verify_constant_table (VerifyContext *ctx)
2900 {
2901 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CONSTANT];
2902 guint32 data [MONO_CONSTANT_SIZE], type;
2903 int i;
2904
2905 for (i = 0; i < table->rows; ++i) {
2906 mono_metadata_decode_row (table, i, data, MONO_CONSTANT_SIZE);
2907 type = data [MONO_CONSTANT_TYPE];
2908
2909 if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_STRING) || type == MONO_TYPE_CLASS))
2910 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Type field 0x%08x", i, type));
2911
2912 if (!is_valid_coded_index (ctx, HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2913 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded index 0x%08x", i, data [MONO_CONSTANT_PARENT]));
2914
2915 if (!get_coded_index_token (HAS_CONSTANT_DESC, data [MONO_CONSTANT_PARENT]))
2916 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Parent field coded is null", i));
2917
2918 if (!is_valid_constant (ctx, type, data [MONO_CONSTANT_VALUE]))
2919 ADD_ERROR (ctx, g_strdup_printf ("Invalid Constant row %d Value field 0x%08x", i, data [MONO_CONSTANT_VALUE]));
2920 }
2921 }
2922
2923 static void
verify_cattr_table(VerifyContext * ctx)2924 verify_cattr_table (VerifyContext *ctx)
2925 {
2926 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2927 guint32 data [MONO_CUSTOM_ATTR_SIZE];
2928 int i;
2929
2930 for (i = 0; i < table->rows; ++i) {
2931 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2932
2933 if (!is_valid_coded_index (ctx, HAS_CATTR_DESC, data [MONO_CUSTOM_ATTR_PARENT]))
2934 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
2935
2936 if (!is_valid_coded_index (ctx, CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]) || !get_coded_index_token (CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]))
2937 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Type field 0x%08x", i, data [MONO_CUSTOM_ATTR_TYPE]));
2938
2939 if (data [MONO_CUSTOM_ATTR_VALUE] && !is_valid_blob_object (ctx, data [MONO_CUSTOM_ATTR_VALUE], 0))
2940 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d invalid value blob 0x%x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2941 }
2942 }
2943
2944 static void
verify_cattr_table_full(VerifyContext * ctx)2945 verify_cattr_table_full (VerifyContext *ctx)
2946 {
2947 MonoError error;
2948 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2949 MonoMethod *ctor;
2950 const char *ptr;
2951 guint32 data [MONO_CUSTOM_ATTR_SIZE], mtoken, size;
2952 int i;
2953
2954 for (i = 0; i < table->rows; ++i) {
2955 mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
2956
2957 if (!is_valid_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
2958 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
2959
2960 mtoken = data [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
2961 switch (data [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
2962 case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
2963 mtoken |= MONO_TOKEN_METHOD_DEF;
2964 break;
2965 case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
2966 mtoken |= MONO_TOKEN_MEMBER_REF;
2967 break;
2968 default:
2969 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute constructor row %d Token 0x%08x", i, data [MONO_CUSTOM_ATTR_TYPE]));
2970 }
2971
2972 ctor = mono_get_method_checked (ctx->image, mtoken, NULL, NULL, &error);
2973
2974 if (!ctor) {
2975 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute content row %d Could not load ctor due to %s", i, mono_error_get_message (&error)));
2976 mono_error_cleanup (&error);
2977 }
2978
2979 /*This can't fail since this is checked in is_valid_cattr_blob*/
2980 g_assert (decode_signature_header (ctx, data [MONO_CUSTOM_ATTR_VALUE], &size, &ptr));
2981
2982 if (!is_valid_cattr_content (ctx, ctor, ptr, size)) {
2983 char *ctor_name = mono_method_full_name (ctor, TRUE);
2984 ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute content row %d Value field 0x%08x ctor: %s", i, data [MONO_CUSTOM_ATTR_VALUE], ctor_name));
2985 g_free (ctor_name);
2986 }
2987 }
2988 }
2989
2990 static void
verify_field_marshal_table(VerifyContext * ctx)2991 verify_field_marshal_table (VerifyContext *ctx)
2992 {
2993 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
2994 guint32 data [MONO_FIELD_MARSHAL_SIZE];
2995 int i;
2996
2997 for (i = 0; i < table->rows; ++i) {
2998 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
2999
3000 if (!is_valid_coded_index (ctx, HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
3001 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field 0x%08x", i, data [MONO_FIELD_MARSHAL_PARENT]));
3002
3003 if (!get_coded_index_token (HAS_FIELD_MARSHAL_DESC, data [MONO_FIELD_MARSHAL_PARENT]))
3004 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d Parent field is null", i));
3005
3006 if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
3007 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
3008
3009 if (!is_valid_blob_object (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE], 1))
3010 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d invalid NativeType blob 0x%x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
3011 }
3012 }
3013
3014 static void
verify_field_marshal_table_full(VerifyContext * ctx)3015 verify_field_marshal_table_full (VerifyContext *ctx)
3016 {
3017 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
3018 guint32 data [MONO_FIELD_MARSHAL_SIZE];
3019 int i;
3020
3021 for (i = 0; i < table->rows; ++i) {
3022 mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
3023
3024 if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
3025 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
3026 }
3027 }
3028
3029 static void
verify_decl_security_table(VerifyContext * ctx)3030 verify_decl_security_table (VerifyContext *ctx)
3031 {
3032 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
3033 guint32 data [MONO_DECL_SECURITY_SIZE];
3034 int i;
3035
3036 for (i = 0; i < table->rows; ++i) {
3037 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
3038
3039 if (!is_valid_coded_index (ctx, HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
3040 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field 0x%08x", i, data [MONO_DECL_SECURITY_PARENT]));
3041
3042 if (!get_coded_index_token (HAS_DECL_SECURITY_DESC, data [MONO_DECL_SECURITY_PARENT]))
3043 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d Parent field is null", i));
3044
3045 if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
3046 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
3047 }
3048 }
3049
3050 static void
verify_decl_security_table_full(VerifyContext * ctx)3051 verify_decl_security_table_full (VerifyContext *ctx)
3052 {
3053 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
3054 guint32 data [MONO_DECL_SECURITY_SIZE];
3055 int i;
3056
3057 for (i = 0; i < table->rows; ++i) {
3058 mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
3059
3060 if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
3061 ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
3062 }
3063 }
3064
3065 static void
verify_class_layout_table(VerifyContext * ctx)3066 verify_class_layout_table (VerifyContext *ctx)
3067 {
3068 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CLASSLAYOUT];
3069 guint32 data [MONO_CLASS_LAYOUT_SIZE];
3070 int i;
3071
3072 for (i = 0; i < table->rows; ++i) {
3073 mono_metadata_decode_row (table, i, data, MONO_CLASS_LAYOUT_SIZE);
3074
3075 if (!data [MONO_CLASS_LAYOUT_PARENT] || data[MONO_CLASS_LAYOUT_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3076 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Parent field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
3077
3078 switch (data [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
3079 case 0:
3080 case 1:
3081 case 2:
3082 case 4:
3083 case 8:
3084 case 16:
3085 case 32:
3086 case 64:
3087 case 128:
3088 break;
3089 default:
3090 ADD_ERROR (ctx, g_strdup_printf ("Invalid ClassLayout row %d Packing field %d", i, data [MONO_CLASS_LAYOUT_PACKING_SIZE]));
3091 }
3092 }
3093 }
3094
3095 static void
verify_field_layout_table(VerifyContext * ctx)3096 verify_field_layout_table (VerifyContext *ctx)
3097 {
3098 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDLAYOUT];
3099 guint32 data [MONO_FIELD_LAYOUT_SIZE];
3100 int i;
3101
3102 for (i = 0; i < table->rows; ++i) {
3103 mono_metadata_decode_row (table, i, data, MONO_FIELD_LAYOUT_SIZE);
3104
3105 if (!data [MONO_FIELD_LAYOUT_FIELD] || data[MONO_FIELD_LAYOUT_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
3106 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldLayout row %d Field field 0x%08x", i, data [MONO_FIELD_LAYOUT_FIELD]));
3107 }
3108 }
3109
3110 static void
verify_standalonesig_table(VerifyContext * ctx)3111 verify_standalonesig_table (VerifyContext *ctx)
3112 {
3113 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
3114 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
3115 int i;
3116
3117 for (i = 0; i < table->rows; ++i) {
3118 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
3119
3120 if (data [MONO_STAND_ALONE_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_STAND_ALONE_SIGNATURE], 1))
3121 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d invalid signature 0x%x", i, data [MONO_STAND_ALONE_SIGNATURE]));
3122 }
3123 }
3124
3125 static void
verify_standalonesig_table_full(VerifyContext * ctx)3126 verify_standalonesig_table_full (VerifyContext *ctx)
3127 {
3128 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
3129 guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
3130 int i;
3131
3132 for (i = 0; i < table->rows; ++i) {
3133 mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
3134
3135 if (!is_valid_standalonesig_blob (ctx, data [MONO_STAND_ALONE_SIGNATURE]))
3136 ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d Signature field 0x%08x", i, data [MONO_STAND_ALONE_SIGNATURE]));
3137 }
3138 }
3139
3140 static void
verify_eventmap_table(VerifyContext * ctx)3141 verify_eventmap_table (VerifyContext *ctx)
3142 {
3143 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENTMAP];
3144 guint32 data [MONO_EVENT_MAP_SIZE], eventlist = 0;
3145 int i;
3146
3147 for (i = 0; i < table->rows; ++i) {
3148 mono_metadata_decode_row (table, i, data, MONO_EVENT_MAP_SIZE);
3149
3150 if (!data [MONO_EVENT_MAP_PARENT] || data [MONO_EVENT_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3151 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d Parent field 0x%08x", i, data [MONO_EVENT_MAP_PARENT]));
3152
3153 if (!data [MONO_EVENT_MAP_EVENTLIST] || data [MONO_EVENT_MAP_EVENTLIST] <= eventlist)
3154 ADD_ERROR (ctx, g_strdup_printf ("Invalid EventMap row %d EventList field %d", i, data [MONO_EVENT_MAP_EVENTLIST]));
3155
3156 eventlist = data [MONO_EVENT_MAP_EVENTLIST];
3157 }
3158 }
3159
3160 #define INVALID_EVENT_FLAGS_BITS ~((1 << 9) | (1 << 10))
3161 static void
verify_event_table(VerifyContext * ctx)3162 verify_event_table (VerifyContext *ctx)
3163 {
3164 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
3165 guint32 data [MONO_EVENT_SIZE];
3166 int i;
3167
3168 for (i = 0; i < table->rows; ++i) {
3169 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
3170
3171 if (data [MONO_EVENT_FLAGS] & INVALID_EVENT_FLAGS_BITS)
3172 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventFlags field %08x", i, data [MONO_EVENT_FLAGS]));
3173
3174 if (!is_valid_non_empty_string (ctx, data [MONO_EVENT_NAME]))
3175 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d Name field %08x", i, data [MONO_EVENT_NAME]));
3176
3177 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
3178 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
3179 }
3180 }
3181
3182 static void
verify_event_table_full(VerifyContext * ctx)3183 verify_event_table_full (VerifyContext *ctx)
3184 {
3185 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
3186 MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
3187 guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
3188 gboolean found_add, found_remove;
3189 int i, idx;
3190
3191 for (i = 0; i < table->rows; ++i) {
3192 mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
3193
3194 token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
3195 idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
3196 if (idx == -1)
3197 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn or RemoveOn associated methods", i));
3198
3199 //first we move to the first row for this event
3200 while (idx > 0) {
3201 if (mono_metadata_decode_row_col (sema_table, idx - 1, MONO_METHOD_SEMA_ASSOCIATION) != token)
3202 break;
3203 --idx;
3204 }
3205 //now move forward looking for AddOn and RemoveOn rows
3206 found_add = found_remove = FALSE;
3207 while (idx < sema_table->rows) {
3208 mono_metadata_decode_row (sema_table, idx, sema_data, MONO_METHOD_SEMA_SIZE);
3209 if (sema_data [MONO_METHOD_SEMA_ASSOCIATION] != token)
3210 break;
3211 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_ADD_ON)
3212 found_add = TRUE;
3213 if (sema_data [MONO_METHOD_SEMA_SEMANTICS] & METHOD_SEMANTIC_REMOVE_ON)
3214 found_remove = TRUE;
3215 if (found_add && found_remove)
3216 break;
3217 ++idx;
3218 }
3219
3220 if (!found_add)
3221 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no AddOn associated method", i));
3222 if (!found_remove)
3223 ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d has no RemoveOn associated method", i));
3224 }
3225 }
3226
3227 static void
verify_propertymap_table(VerifyContext * ctx)3228 verify_propertymap_table (VerifyContext *ctx)
3229 {
3230 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTYMAP];
3231 guint32 data [MONO_PROPERTY_MAP_SIZE], propertylist = 0;
3232 int i;
3233
3234 for (i = 0; i < table->rows; ++i) {
3235 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_MAP_SIZE);
3236
3237 if (!data [MONO_PROPERTY_MAP_PARENT] || data [MONO_PROPERTY_MAP_PARENT] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3238 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d Parent field 0x%08x", i, data [MONO_PROPERTY_MAP_PARENT]));
3239
3240 if (!data [MONO_PROPERTY_MAP_PROPERTY_LIST] || data [MONO_PROPERTY_MAP_PROPERTY_LIST] <= propertylist)
3241 ADD_ERROR (ctx, g_strdup_printf ("Invalid PropertyMap row %d PropertyList field %d", i, data [MONO_PROPERTY_MAP_PROPERTY_LIST]));
3242
3243 propertylist = data [MONO_PROPERTY_MAP_PROPERTY_LIST];
3244 }
3245 }
3246
3247 #define INVALID_PROPERTY_FLAGS_BITS ~((1 << 9) | (1 << 10) | (1 << 12))
3248 static void
verify_property_table(VerifyContext * ctx)3249 verify_property_table (VerifyContext *ctx)
3250 {
3251 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PROPERTY];
3252 guint32 data [MONO_PROPERTY_SIZE];
3253 int i;
3254
3255 for (i = 0; i < table->rows; ++i) {
3256 mono_metadata_decode_row (table, i, data, MONO_PROPERTY_SIZE);
3257
3258 if (data [MONO_PROPERTY_FLAGS] & INVALID_PROPERTY_FLAGS_BITS)
3259 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d PropertyFlags field %08x", i, data [MONO_PROPERTY_FLAGS]));
3260
3261 if (!is_valid_non_empty_string (ctx, data [MONO_PROPERTY_NAME]))
3262 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Name field %08x", i, data [MONO_PROPERTY_NAME]));
3263
3264 if (!is_valid_property_sig_blob (ctx, data [MONO_PROPERTY_TYPE]))
3265 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d Type field %08x", i, data [MONO_PROPERTY_TYPE]));
3266
3267 if ((data [MONO_PROPERTY_FLAGS] & PROPERTY_ATTRIBUTE_HAS_DEFAULT) &&
3268 search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PROPERTY, i)) == -1)
3269 ADD_ERROR (ctx, g_strdup_printf ("Invalid Property row %d has HasDefault but there is no corresponding row in the Constant table", i));
3270
3271 }
3272 }
3273
3274 static void
verify_methodimpl_table(VerifyContext * ctx)3275 verify_methodimpl_table (VerifyContext *ctx)
3276 {
3277 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
3278 guint32 data [MONO_METHODIMPL_SIZE];
3279 int i;
3280
3281 for (i = 0; i < table->rows; ++i) {
3282 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
3283
3284 if (!data [MONO_METHODIMPL_CLASS] || data [MONO_METHODIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows + 1)
3285 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d Class field %08x", i, data [MONO_TABLE_TYPEDEF]));
3286
3287 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
3288 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
3289
3290 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_BODY]))
3291 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodBody field %08x", i, data [MONO_METHODIMPL_BODY]));
3292
3293 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
3294 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
3295
3296 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODIMPL_DECLARATION]))
3297 ADD_ERROR (ctx, g_strdup_printf ("Invalid MethodImpl row %d MethodDeclaration field %08x", i, data [MONO_METHODIMPL_DECLARATION]));
3298 }
3299 }
3300
3301 static void
verify_moduleref_table(VerifyContext * ctx)3302 verify_moduleref_table (VerifyContext *ctx)
3303 {
3304 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULEREF];
3305 guint32 data [MONO_MODULEREF_SIZE];
3306 int i;
3307
3308 for (i = 0; i < table->rows; ++i) {
3309 mono_metadata_decode_row (table, i, data, MONO_MODULEREF_SIZE);
3310
3311 if (!is_valid_non_empty_string (ctx, data[MONO_MODULEREF_NAME]))
3312 ADD_ERROR (ctx, g_strdup_printf ("Invalid ModuleRef row %d name field %08x", i, data [MONO_MODULEREF_NAME]));
3313 }
3314 }
3315
3316 static void
verify_typespec_table(VerifyContext * ctx)3317 verify_typespec_table (VerifyContext *ctx)
3318 {
3319 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
3320 guint32 data [MONO_TYPESPEC_SIZE];
3321 int i;
3322
3323 for (i = 0; i < table->rows; ++i) {
3324 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
3325
3326 if (data [MONO_TYPESPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_TYPESPEC_SIGNATURE], 1))
3327 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
3328 }
3329 }
3330
3331 static void
verify_typespec_table_full(VerifyContext * ctx)3332 verify_typespec_table_full (VerifyContext *ctx)
3333 {
3334 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
3335 guint32 data [MONO_TYPESPEC_SIZE];
3336 int i;
3337
3338 for (i = 0; i < table->rows; ++i) {
3339 mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
3340 ctx->token = (i + 1) | MONO_TOKEN_TYPE_SPEC;
3341 if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
3342 ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
3343 }
3344 ctx->token = 0;
3345 }
3346
3347 #define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 12) | (1 << 13))
3348 static void
verify_implmap_table(VerifyContext * ctx)3349 verify_implmap_table (VerifyContext *ctx)
3350 {
3351 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_IMPLMAP];
3352 guint32 data [MONO_IMPLMAP_SIZE], cconv;
3353 int i;
3354
3355 for (i = 0; i < table->rows; ++i) {
3356 mono_metadata_decode_row (table, i, data, MONO_IMPLMAP_SIZE);
3357
3358 if (data [MONO_IMPLMAP_FLAGS] & INVALID_IMPLMAP_FLAGS_BITS)
3359 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Flags field %08x", i, data [MONO_IMPLMAP_FLAGS]));
3360
3361 cconv = data [MONO_IMPLMAP_FLAGS] & PINVOKE_ATTRIBUTE_CALL_CONV_MASK;
3362 if (cconv == 0 || cconv == 0x0600 || cconv == 0x0700)
3363 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid call conv field %x", i, cconv));
3364
3365 if (!is_valid_coded_index (ctx, MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
3366 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid MemberForward token %x", i, data [MONO_IMPLMAP_MEMBER]));
3367
3368 if (get_coded_index_table (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]) != MONO_TABLE_METHOD)
3369 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d only methods are supported token %x", i, data [MONO_IMPLMAP_MEMBER]));
3370
3371 if (!get_coded_index_token (MEMBER_FORWARDED_DESC, data [MONO_IMPLMAP_MEMBER]))
3372 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d null token", i));
3373
3374 if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
3375 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
3376
3377 if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULEREF].rows)
3378 ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
3379 }
3380 }
3381
3382 static void
verify_fieldrva_table(VerifyContext * ctx)3383 verify_fieldrva_table (VerifyContext *ctx)
3384 {
3385 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDRVA];
3386 guint32 data [MONO_FIELD_RVA_SIZE];
3387 int i;
3388
3389 for (i = 0; i < table->rows; ++i) {
3390 mono_metadata_decode_row (table, i, data, MONO_FIELD_RVA_SIZE);
3391
3392 if (!data [MONO_FIELD_RVA_RVA] || mono_cli_rva_image_map (ctx->image, data [MONO_FIELD_RVA_RVA]) == INVALID_ADDRESS)
3393 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d RVA %08x", i, data [MONO_FIELD_RVA_RVA]));
3394
3395 if (!data [MONO_FIELD_RVA_FIELD] || data [MONO_FIELD_RVA_FIELD] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
3396 ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldRVA row %d Field %08x", i, data [MONO_FIELD_RVA_FIELD]));
3397 }
3398 }
3399
3400 #define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 14) | (1 << 15))
3401 static void
verify_assembly_table(VerifyContext * ctx)3402 verify_assembly_table (VerifyContext *ctx)
3403 {
3404 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLY];
3405 guint32 data [MONO_ASSEMBLY_SIZE], hash;
3406 int i;
3407
3408 if (table->rows > 1)
3409 ADD_ERROR (ctx, g_strdup_printf ("Assembly table can have zero or one rows, but now %d", table->rows));
3410
3411 for (i = 0; i < table->rows; ++i) {
3412 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLY_SIZE);
3413
3414 hash = data [MONO_ASSEMBLY_HASH_ALG];
3415 if (!(hash == 0 || hash == 0x8003 || hash == 0x8004))
3416 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid HashAlgId %x", i, hash));
3417
3418 if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
3419 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
3420
3421 if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY], 1))
3422 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
3423
3424 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
3425 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Name %08x", i, data [MONO_ASSEMBLY_NAME]));
3426
3427 if (data [MONO_ASSEMBLY_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLY_CULTURE]))
3428 ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLY_CULTURE]));
3429 }
3430 }
3431
3432 #define INVALID_ASSEMBLYREF_FLAGS_BITS ~((1 << 0) | (1 << 8) | (1 << 14) | (1 << 15))
3433 static void
verify_assemblyref_table(VerifyContext * ctx)3434 verify_assemblyref_table (VerifyContext *ctx)
3435 {
3436 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_ASSEMBLYREF];
3437 guint32 data [MONO_ASSEMBLYREF_SIZE];
3438 int i;
3439
3440 for (i = 0; i < table->rows; ++i) {
3441 mono_metadata_decode_row (table, i, data, MONO_ASSEMBLYREF_SIZE);
3442
3443 if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
3444 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
3445
3446 if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY], 1))
3447 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
3448
3449 if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
3450 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Name %08x", i, data [MONO_ASSEMBLYREF_NAME]));
3451
3452 if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
3453 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
3454
3455 if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE], 1))
3456 ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
3457 }
3458 }
3459
3460 #define INVALID_FILE_FLAGS_BITS ~(1)
3461 static void
verify_file_table(VerifyContext * ctx)3462 verify_file_table (VerifyContext *ctx)
3463 {
3464 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FILE];
3465 guint32 data [MONO_FILE_SIZE];
3466 int i;
3467
3468 for (i = 0; i < table->rows; ++i) {
3469 mono_metadata_decode_row (table, i, data, MONO_FILE_SIZE);
3470
3471 if (data [MONO_FILE_FLAGS] & INVALID_FILE_FLAGS_BITS)
3472 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Flags %08x", i, data [MONO_FILE_FLAGS]));
3473
3474 if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
3475 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
3476
3477 if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE], 1))
3478 ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
3479 }
3480 }
3481
3482 #define INVALID_EXPORTED_TYPE_FLAGS_BITS (INVALID_TYPEDEF_FLAG_BITS & ~TYPE_ATTRIBUTE_FORWARDER)
3483 static void
verify_exportedtype_table(VerifyContext * ctx)3484 verify_exportedtype_table (VerifyContext *ctx)
3485 {
3486 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EXPORTEDTYPE];
3487 guint32 data [MONO_EXP_TYPE_SIZE];
3488 int i;
3489
3490 for (i = 0; i < table->rows; ++i) {
3491 mono_metadata_decode_row (table, i, data, MONO_EXP_TYPE_SIZE);
3492
3493 if (data [MONO_EXP_TYPE_FLAGS] & INVALID_EXPORTED_TYPE_FLAGS_BITS)
3494 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Flags %08x", i, data [MONO_EXP_TYPE_FLAGS]));
3495
3496 if (!is_valid_non_empty_string (ctx, data [MONO_EXP_TYPE_NAME]))
3497 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeName %08x", i, data [MONO_FILE_NAME]));
3498
3499 if (data [MONO_EXP_TYPE_NAMESPACE] && !is_valid_string (ctx, data [MONO_EXP_TYPE_NAMESPACE]))
3500 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid TypeNamespace %08x", i, data [MONO_EXP_TYPE_NAMESPACE]));
3501
3502 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3503 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has invalid Implementation token %08x", i, data [MONO_EXP_TYPE_IMPLEMENTATION]));
3504
3505 if (!get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]))
3506 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has null Implementation token", i));
3507
3508 /*nested type can't have a namespace*/
3509 if (get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_EXP_TYPE_IMPLEMENTATION]) == MONO_TABLE_EXPORTEDTYPE && data [MONO_EXP_TYPE_NAMESPACE])
3510 ADD_ERROR (ctx, g_strdup_printf ("ExportedType table row %d has denotes a nested type but has a non null TypeNamespace", i));
3511 }
3512 }
3513
3514 #define INVALID_MANIFEST_RESOURCE_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
3515 static void
verify_manifest_resource_table(VerifyContext * ctx)3516 verify_manifest_resource_table (VerifyContext *ctx)
3517 {
3518 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)ctx->image->image_info;
3519 MonoCLIHeader *ch = &iinfo->cli_cli_header;
3520 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MANIFESTRESOURCE];
3521 guint32 data [MONO_MANIFEST_SIZE], impl_table, token, resources_size;
3522 int i;
3523
3524 resources_size = ch->ch_resources.size;
3525
3526 for (i = 0; i < table->rows; ++i) {
3527 mono_metadata_decode_row (table, i, data, MONO_MANIFEST_SIZE);
3528
3529 if (data [MONO_MANIFEST_FLAGS] & INVALID_MANIFEST_RESOURCE_FLAGS_BITS)
3530 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags %08x", i, data [MONO_MANIFEST_FLAGS]));
3531
3532 if (data [MONO_MANIFEST_FLAGS] != 1 && data [MONO_MANIFEST_FLAGS] != 2)
3533 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Flags VisibilityMask %08x", i, data [MONO_MANIFEST_FLAGS]));
3534
3535 if (!is_valid_non_empty_string (ctx, data [MONO_MANIFEST_NAME]))
3536 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Name %08x", i, data [MONO_MANIFEST_NAME]));
3537
3538 if (!is_valid_coded_index (ctx, IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]))
3539 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d has invalid Implementation token %08x", i, data [MONO_MANIFEST_IMPLEMENTATION]));
3540
3541 impl_table = get_coded_index_table (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3542 token = get_coded_index_token (IMPLEMENTATION_DESC, data [MONO_MANIFEST_IMPLEMENTATION]);
3543
3544 if (impl_table == MONO_TABLE_EXPORTEDTYPE)
3545 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])));
3546
3547 if (impl_table == MONO_TABLE_FILE && token && data [MONO_MANIFEST_OFFSET])
3548 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d points to a file but has non-zero offset", i));
3549
3550 if (!token && data [MONO_MANIFEST_OFFSET] >= resources_size)
3551 ADD_ERROR (ctx, g_strdup_printf ("ManifestResource table row %d invalid Offset field %08x ", i, data [MONO_MANIFEST_OFFSET]));
3552 }
3553 }
3554
3555 static void
verify_nested_class_table(VerifyContext * ctx)3556 verify_nested_class_table (VerifyContext *ctx)
3557 {
3558 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3559 guint32 data [MONO_NESTED_CLASS_SIZE];
3560 int i;
3561
3562 for (i = 0; i < table->rows; ++i) {
3563 mono_metadata_decode_row (table, i, data, MONO_NESTED_CLASS_SIZE);
3564
3565 if (!data [MONO_NESTED_CLASS_NESTED] || data [MONO_NESTED_CLASS_NESTED] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3566 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid NestedClass token %08x", i, data [MONO_NESTED_CLASS_NESTED]));
3567 if (!data [MONO_NESTED_CLASS_ENCLOSING] || data [MONO_NESTED_CLASS_ENCLOSING] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
3568 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has invalid EnclosingClass token %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3569 if (data [MONO_NESTED_CLASS_ENCLOSING] == data [MONO_NESTED_CLASS_NESTED])
3570 ADD_ERROR (ctx, g_strdup_printf ("NestedClass table row %d has same token for NestedClass and EnclosingClass %08x", i, data [MONO_NESTED_CLASS_ENCLOSING]));
3571 }
3572 }
3573
3574 #define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
3575 static void
verify_generic_param_table(VerifyContext * ctx)3576 verify_generic_param_table (VerifyContext *ctx)
3577 {
3578 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAM];
3579 guint32 data [MONO_GENERICPARAM_SIZE], token, last_token = 0;
3580 int i, param_number = 0;
3581
3582 for (i = 0; i < table->rows; ++i) {
3583 mono_metadata_decode_row (table, i, data, MONO_GENERICPARAM_SIZE);
3584
3585 if (data [MONO_GENERICPARAM_FLAGS] & INVALID_GENERIC_PARAM_FLAGS_BITS)
3586 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Flags token %08x", i, data [MONO_GENERICPARAM_FLAGS]));
3587
3588 if ((data [MONO_GENERICPARAM_FLAGS] & MONO_GEN_PARAM_VARIANCE_MASK) == 0x3)
3589 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid VarianceMask 0x3", i));
3590
3591 if (!is_valid_non_empty_string (ctx, data [MONO_GENERICPARAM_NAME]))
3592 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Name token %08x", i, data [MONO_GENERICPARAM_NAME]));
3593
3594 token = data [MONO_GENERICPARAM_OWNER];
3595
3596 if (!is_valid_coded_index (ctx, TYPE_OR_METHODDEF_DESC, token))
3597 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has invalid Owner token %08x", i, token));
3598
3599 if (!get_coded_index_token (TYPE_OR_METHODDEF_DESC, token))
3600 ADD_ERROR (ctx, g_strdup_printf ("GenericParam table row %d has null Owner token", i));
3601
3602 if (token != last_token) {
3603 param_number = 0;
3604 last_token = token;
3605 }
3606
3607 if (data [MONO_GENERICPARAM_NUMBER] != param_number)
3608 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));
3609
3610 ++param_number;
3611 }
3612 }
3613
3614 static void
verify_method_spec_table(VerifyContext * ctx)3615 verify_method_spec_table (VerifyContext *ctx)
3616 {
3617 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3618 guint32 data [MONO_METHODSPEC_SIZE];
3619 int i;
3620
3621 for (i = 0; i < table->rows; ++i) {
3622 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3623
3624 if (!is_valid_coded_index (ctx, METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3625 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Method token %08x", i, data [MONO_METHODSPEC_METHOD]));
3626
3627 if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
3628 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
3629
3630 if (data [MONO_METHODSPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHODSPEC_SIGNATURE], 1))
3631 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid signature token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3632 }
3633 }
3634
3635 static void
verify_method_spec_table_full(VerifyContext * ctx)3636 verify_method_spec_table_full (VerifyContext *ctx)
3637 {
3638 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
3639 guint32 data [MONO_METHODSPEC_SIZE];
3640 int i;
3641
3642 for (i = 0; i < table->rows; ++i) {
3643 mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
3644
3645 if (!is_valid_methodspec_blob (ctx, data [MONO_METHODSPEC_SIGNATURE]))
3646 ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
3647 }
3648 }
3649
3650 static void
verify_generic_param_constraint_table(VerifyContext * ctx)3651 verify_generic_param_constraint_table (VerifyContext *ctx)
3652 {
3653 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
3654 guint32 data [MONO_GENPARCONSTRAINT_SIZE];
3655 int i;
3656 guint32 last_owner = 0, last_constraint = 0;
3657
3658 for (i = 0; i < table->rows; ++i) {
3659 mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
3660
3661 if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
3662 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_GENPARCONSTRAINT_GENERICPAR]));
3663
3664 if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3665 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
3666
3667 if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
3668 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
3669
3670 if (last_owner > data [MONO_GENPARCONSTRAINT_GENERICPAR])
3671 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d is not properly sorted. Previous value of the owner column is 0x%08x current value is 0x%08x", i, last_owner, data [MONO_GENPARCONSTRAINT_GENERICPAR]));
3672
3673 if (last_owner == data [MONO_GENPARCONSTRAINT_GENERICPAR]) {
3674 if (last_constraint == data [MONO_GENPARCONSTRAINT_CONSTRAINT])
3675 ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has duplicate constraint 0x%08x", i, last_constraint));
3676 } else {
3677 last_owner = data [MONO_GENPARCONSTRAINT_GENERICPAR];
3678 }
3679 last_constraint = data [MONO_GENPARCONSTRAINT_CONSTRAINT];
3680 }
3681 }
3682
3683
3684 typedef struct {
3685 const char *name;
3686 const char *name_space;
3687 guint32 resolution_scope;
3688 } TypeDefUniqueId;
3689
3690 static guint
typedef_hash(gconstpointer _key)3691 typedef_hash (gconstpointer _key)
3692 {
3693 const TypeDefUniqueId *key = (const TypeDefUniqueId *)_key;
3694 return g_str_hash (key->name) ^ g_str_hash (key->name_space) ^ key->resolution_scope; /*XXX better salt the int key*/
3695 }
3696
3697 static gboolean
typedef_equals(gconstpointer _a,gconstpointer _b)3698 typedef_equals (gconstpointer _a, gconstpointer _b)
3699 {
3700 const TypeDefUniqueId *a = (const TypeDefUniqueId *)_a;
3701 const TypeDefUniqueId *b = (const TypeDefUniqueId *)_b;
3702 return !strcmp (a->name, b->name) && !strcmp (a->name_space, b->name_space) && a->resolution_scope == b->resolution_scope;
3703 }
3704
3705 static void
verify_typedef_table_global_constraints(VerifyContext * ctx)3706 verify_typedef_table_global_constraints (VerifyContext *ctx)
3707 {
3708 int i;
3709 guint32 data [MONO_TYPEDEF_SIZE];
3710 guint32 nested_data [MONO_NESTED_CLASS_SIZE];
3711 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
3712 MonoTableInfo *nested_table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
3713 GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3714
3715 for (i = 0; i < table->rows; ++i) {
3716 guint visibility;
3717 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3718 mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
3719
3720 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAME]);
3721 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAMESPACE]);
3722 type->resolution_scope = 0;
3723
3724 visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
3725 if (visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) {
3726 int res = search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1);
3727 g_assert (res >= 0);
3728
3729 mono_metadata_decode_row (nested_table, res, nested_data, MONO_NESTED_CLASS_SIZE);
3730 type->resolution_scope = nested_data [MONO_NESTED_CLASS_ENCLOSING];
3731 }
3732
3733 if (g_hash_table_lookup (unique_types, type)) {
3734 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("TypeDef table row %d has duplicate for tuple (%s,%s,%x)", i, type->name, type->name_space, type->resolution_scope));
3735 g_hash_table_destroy (unique_types);
3736 g_free (type);
3737 return;
3738 }
3739 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3740 }
3741
3742 g_hash_table_destroy (unique_types);
3743 }
3744
3745 static void
verify_typeref_table_global_constraints(VerifyContext * ctx)3746 verify_typeref_table_global_constraints (VerifyContext *ctx)
3747 {
3748 int i;
3749 guint32 data [MONO_TYPEREF_SIZE];
3750 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
3751 GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
3752
3753 for (i = 0; i < table->rows; ++i) {
3754 TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
3755 mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
3756
3757 type->resolution_scope = data [MONO_TYPEREF_SCOPE];
3758 type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAME]);
3759 type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAMESPACE]);
3760
3761 if (g_hash_table_lookup (unique_types, type)) {
3762 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("TypeRef table row %d has duplicate for tuple (%s,%s,%x)", i, type->name, type->name_space, type->resolution_scope));
3763 g_hash_table_destroy (unique_types);
3764 g_free (type);
3765 return;
3766 }
3767 g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
3768 }
3769
3770 g_hash_table_destroy (unique_types);
3771 }
3772
3773 typedef struct {
3774 guint32 klass;
3775 guint32 method_declaration;
3776 } MethodImplUniqueId;
3777
3778 static guint
methodimpl_hash(gconstpointer _key)3779 methodimpl_hash (gconstpointer _key)
3780 {
3781 const MethodImplUniqueId *key = (const MethodImplUniqueId *)_key;
3782 return key->klass ^ key->method_declaration;
3783 }
3784
3785 static gboolean
methodimpl_equals(gconstpointer _a,gconstpointer _b)3786 methodimpl_equals (gconstpointer _a, gconstpointer _b)
3787 {
3788 const MethodImplUniqueId *a = (const MethodImplUniqueId *)_a;
3789 const MethodImplUniqueId *b = (const MethodImplUniqueId *)_b;
3790 return a->klass == b->klass && a->method_declaration == b->method_declaration;
3791 }
3792
3793 static void
verify_methodimpl_table_global_constraints(VerifyContext * ctx)3794 verify_methodimpl_table_global_constraints (VerifyContext *ctx)
3795 {
3796 int i;
3797 guint32 data [MONO_METHODIMPL_SIZE];
3798 MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODIMPL];
3799 GHashTable *unique_impls = g_hash_table_new_full (&methodimpl_hash, &methodimpl_equals, g_free, NULL);
3800
3801 for (i = 0; i < table->rows; ++i) {
3802 MethodImplUniqueId *impl = g_new (MethodImplUniqueId, 1);
3803 mono_metadata_decode_row (table, i, data, MONO_METHODIMPL_SIZE);
3804
3805 impl->klass = data [MONO_METHODIMPL_CLASS];
3806 impl->method_declaration = data [MONO_METHODIMPL_DECLARATION];
3807
3808 if (g_hash_table_lookup (unique_impls, impl)) {
3809 ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("MethodImpl table row %d has duplicate for tuple (0x%x, 0x%x)", impl->klass, impl->method_declaration));
3810 g_hash_table_destroy (unique_impls);
3811 g_free (impl);
3812 return;
3813 }
3814 g_hash_table_insert (unique_impls, impl, GUINT_TO_POINTER (1));
3815 }
3816
3817 g_hash_table_destroy (unique_impls);
3818 }
3819
3820
3821 static void
verify_tables_data_global_constraints(VerifyContext * ctx)3822 verify_tables_data_global_constraints (VerifyContext *ctx)
3823 {
3824 verify_typedef_table_global_constraints (ctx);
3825 }
3826
3827 static void
verify_tables_data_global_constraints_full(VerifyContext * ctx)3828 verify_tables_data_global_constraints_full (VerifyContext *ctx)
3829 {
3830 verify_typeref_table (ctx);
3831 verify_typeref_table_global_constraints (ctx);
3832 verify_methodimpl_table_global_constraints (ctx);
3833 }
3834
3835 static void
verify_tables_data(VerifyContext * ctx)3836 verify_tables_data (VerifyContext *ctx)
3837 {
3838 OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
3839 guint32 size = 0, tables_offset;
3840 int i;
3841
3842 for (i = 0; i < 0x2D; ++i) {
3843 MonoTableInfo *table = &ctx->image->tables [i];
3844 guint32 tmp_size;
3845 tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
3846 if (tmp_size < size) {
3847 size = 0;
3848 break;
3849 }
3850 size = tmp_size;
3851 }
3852
3853 if (size == 0)
3854 ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
3855
3856 tables_offset = ctx->image->tables_base - ctx->data;
3857 if (!bounds_check_offset (&tables_area, tables_offset, size))
3858 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)));
3859
3860 verify_module_table (ctx);
3861 CHECK_ERROR ();
3862 /*Obfuscators love to place broken stuff in the typeref table
3863 verify_typeref_table (ctx);
3864 CHECK_ERROR ();*/
3865 verify_typedef_table (ctx);
3866 CHECK_ERROR ();
3867 verify_field_table (ctx);
3868 CHECK_ERROR ();
3869 verify_method_table (ctx);
3870 CHECK_ERROR ();
3871 verify_param_table (ctx);
3872 CHECK_ERROR ();
3873 verify_interfaceimpl_table (ctx);
3874 CHECK_ERROR ();
3875 verify_memberref_table (ctx);
3876 CHECK_ERROR ();
3877 verify_constant_table (ctx);
3878 CHECK_ERROR ();
3879 verify_cattr_table (ctx);
3880 CHECK_ERROR ();
3881 verify_field_marshal_table (ctx);
3882 CHECK_ERROR ();
3883 verify_decl_security_table (ctx);
3884 CHECK_ERROR ();
3885 verify_class_layout_table (ctx);
3886 CHECK_ERROR ();
3887 verify_field_layout_table (ctx);
3888 CHECK_ERROR ();
3889 verify_standalonesig_table (ctx);
3890 CHECK_ERROR ();
3891 verify_eventmap_table (ctx);
3892 CHECK_ERROR ();
3893 verify_event_table (ctx);
3894 CHECK_ERROR ();
3895 verify_propertymap_table (ctx);
3896 CHECK_ERROR ();
3897 verify_property_table (ctx);
3898 CHECK_ERROR ();
3899 verify_methodimpl_table (ctx);
3900 CHECK_ERROR ();
3901 verify_moduleref_table (ctx);
3902 CHECK_ERROR ();
3903 verify_typespec_table (ctx);
3904 CHECK_ERROR ();
3905 verify_implmap_table (ctx);
3906 CHECK_ERROR ();
3907 verify_fieldrva_table (ctx);
3908 CHECK_ERROR ();
3909 verify_assembly_table (ctx);
3910 CHECK_ERROR ();
3911 verify_assemblyref_table (ctx);
3912 CHECK_ERROR ();
3913 verify_file_table (ctx);
3914 CHECK_ERROR ();
3915 verify_exportedtype_table (ctx);
3916 CHECK_ERROR ();
3917 verify_manifest_resource_table (ctx);
3918 CHECK_ERROR ();
3919 verify_nested_class_table (ctx);
3920 CHECK_ERROR ();
3921 verify_generic_param_table (ctx);
3922 CHECK_ERROR ();
3923 verify_method_spec_table (ctx);
3924 CHECK_ERROR ();
3925 verify_generic_param_constraint_table (ctx);
3926 CHECK_ERROR ();
3927 verify_tables_data_global_constraints (ctx);
3928 }
3929
3930 static void
init_verify_context(VerifyContext * ctx,MonoImage * image,gboolean report_error)3931 init_verify_context (VerifyContext *ctx, MonoImage *image, gboolean report_error)
3932 {
3933 memset (ctx, 0, sizeof (VerifyContext));
3934 ctx->image = image;
3935 ctx->report_error = report_error;
3936 ctx->report_warning = FALSE; //export this setting in the API
3937 ctx->valid = 1;
3938 ctx->size = image->raw_data_len;
3939 ctx->data = image->raw_data;
3940 }
3941
3942 static gboolean
cleanup_context(VerifyContext * ctx,GSList ** error_list)3943 cleanup_context (VerifyContext *ctx, GSList **error_list)
3944 {
3945 g_free (ctx->sections);
3946 if (error_list)
3947 *error_list = ctx->errors;
3948 else
3949 mono_free_verify_list (ctx->errors);
3950 return ctx->valid;
3951 }
3952
3953 static gboolean
cleanup_context_checked(VerifyContext * ctx,MonoError * error)3954 cleanup_context_checked (VerifyContext *ctx, MonoError *error)
3955 {
3956 g_free (ctx->sections);
3957 if (ctx->errors) {
3958 MonoVerifyInfo *info = (MonoVerifyInfo *)ctx->errors->data;
3959 mono_error_set_bad_image (error, ctx->image, "%s", info->message);
3960 mono_free_verify_list (ctx->errors);
3961 }
3962 return ctx->valid;
3963 }
3964
3965 gboolean
mono_verifier_verify_pe_data(MonoImage * image,GSList ** error_list)3966 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
3967 {
3968 VerifyContext ctx;
3969
3970 if (!mono_verifier_is_enabled_for_image (image))
3971 return TRUE;
3972
3973 init_verify_context (&ctx, image, error_list != NULL);
3974 ctx.stage = STAGE_PE;
3975
3976 verify_msdos_header (&ctx);
3977 CHECK_STATE();
3978 verify_pe_header (&ctx);
3979 CHECK_STATE();
3980 verify_pe_optional_header (&ctx);
3981 CHECK_STATE();
3982 load_section_table (&ctx);
3983 CHECK_STATE();
3984 load_data_directories (&ctx);
3985 CHECK_STATE();
3986 verify_import_table (&ctx);
3987 CHECK_STATE();
3988 /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
3989 verify_resources_table (&ctx);
3990
3991 cleanup:
3992 return cleanup_context (&ctx, error_list);
3993 }
3994
3995 gboolean
mono_verifier_verify_cli_data(MonoImage * image,GSList ** error_list)3996 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
3997 {
3998 VerifyContext ctx;
3999
4000 if (!mono_verifier_is_enabled_for_image (image))
4001 return TRUE;
4002
4003 init_verify_context (&ctx, image, error_list != NULL);
4004 ctx.stage = STAGE_CLI;
4005
4006 verify_cli_header (&ctx);
4007 CHECK_STATE();
4008 verify_metadata_header (&ctx);
4009 CHECK_STATE();
4010 verify_tables_schema (&ctx);
4011
4012 cleanup:
4013 return cleanup_context (&ctx, error_list);
4014 }
4015
4016
4017 /*
4018 * Verifies basic table constraints such as global table invariants (sorting, field monotonicity, etc).
4019 * Other verification checks are meant to be done lazily by the runtime. Those include:
4020 * blob items (signatures, method headers, custom attributes, etc)
4021 * type semantics related
4022 * vtable related
4023 * stuff that should not block other pieces from running such as bad types/methods/fields/etc.
4024 *
4025 * The whole idea is that if this succeed the runtime is free to play around safely but any complex
4026 * operation still need more checking.
4027 */
4028 gboolean
mono_verifier_verify_table_data(MonoImage * image,GSList ** error_list)4029 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
4030 {
4031 VerifyContext ctx;
4032
4033 if (!mono_verifier_is_enabled_for_image (image))
4034 return TRUE;
4035
4036 init_verify_context (&ctx, image, error_list != NULL);
4037 ctx.stage = STAGE_TABLES;
4038
4039 verify_tables_data (&ctx);
4040
4041 return cleanup_context (&ctx, error_list);
4042 }
4043
4044
4045 /*
4046 * Verifies all other constraints.
4047 */
4048 gboolean
mono_verifier_verify_full_table_data(MonoImage * image,GSList ** error_list)4049 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
4050 {
4051 VerifyContext ctx;
4052
4053 if (!mono_verifier_is_enabled_for_image (image))
4054 return TRUE;
4055
4056 init_verify_context (&ctx, image, error_list != NULL);
4057 ctx.stage = STAGE_TABLES;
4058
4059 verify_typedef_table_full (&ctx);
4060 CHECK_STATE ();
4061 verify_field_table_full (&ctx);
4062 CHECK_STATE ();
4063 verify_method_table_full (&ctx);
4064 CHECK_STATE ();
4065 verify_memberref_table_full (&ctx);
4066 CHECK_STATE ();
4067 verify_cattr_table_full (&ctx);
4068 CHECK_STATE ();
4069 verify_field_marshal_table_full (&ctx);
4070 CHECK_STATE ();
4071 verify_decl_security_table_full (&ctx);
4072 CHECK_STATE ();
4073 verify_standalonesig_table_full (&ctx);
4074 CHECK_STATE ();
4075 verify_event_table_full (&ctx);
4076 CHECK_STATE ();
4077 verify_typespec_table_full (&ctx);
4078 CHECK_STATE ();
4079 verify_method_spec_table_full (&ctx);
4080 CHECK_STATE ();
4081 verify_tables_data_global_constraints_full (&ctx);
4082
4083 cleanup:
4084 return cleanup_context (&ctx, error_list);
4085 }
4086
4087 gboolean
mono_verifier_verify_field_signature(MonoImage * image,guint32 offset,GSList ** error_list)4088 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4089 {
4090 VerifyContext ctx;
4091
4092 if (!mono_verifier_is_enabled_for_image (image))
4093 return TRUE;
4094
4095 init_verify_context (&ctx, image, error_list != NULL);
4096 ctx.stage = STAGE_TABLES;
4097
4098 is_valid_field_signature (&ctx, offset);
4099 return cleanup_context (&ctx, error_list);
4100 }
4101
4102 gboolean
mono_verifier_verify_method_header(MonoImage * image,guint32 offset,GSList ** error_list)4103 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
4104 {
4105 VerifyContext ctx;
4106 guint32 locals_token;
4107
4108 if (!mono_verifier_is_enabled_for_image (image))
4109 return TRUE;
4110
4111 init_verify_context (&ctx, image, error_list != NULL);
4112 ctx.stage = STAGE_TABLES;
4113
4114 is_valid_method_header (&ctx, offset, &locals_token);
4115 if (locals_token) {
4116 guint32 sig_offset = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_STANDALONESIG], locals_token - 1, MONO_STAND_ALONE_SIGNATURE);
4117 is_valid_standalonesig_blob (&ctx, sig_offset);
4118 }
4119
4120 return cleanup_context (&ctx, error_list);
4121 }
4122
4123 gboolean
mono_verifier_verify_method_signature(MonoImage * image,guint32 offset,MonoError * error)4124 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, MonoError *error)
4125 {
4126 VerifyContext ctx;
4127
4128 error_init (error);
4129
4130 if (!mono_verifier_is_enabled_for_image (image))
4131 return TRUE;
4132
4133 init_verify_context (&ctx, image, TRUE);
4134 ctx.stage = STAGE_TABLES;
4135
4136 is_valid_method_signature (&ctx, offset);
4137 /*XXX This returns a bad image exception, it might be the case that the right exception is method load.*/
4138 return cleanup_context_checked (&ctx, error);
4139 }
4140
4141 gboolean
mono_verifier_verify_memberref_method_signature(MonoImage * image,guint32 offset,GSList ** error_list)4142 mono_verifier_verify_memberref_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
4143 {
4144 VerifyContext ctx;
4145
4146 if (!mono_verifier_is_enabled_for_image (image))
4147 return TRUE;
4148
4149 init_verify_context (&ctx, image, error_list != NULL);
4150 ctx.stage = STAGE_TABLES;
4151
4152 is_valid_memberref_method_signature (&ctx, offset);
4153 return cleanup_context (&ctx, error_list);
4154 }
4155
4156 gboolean
mono_verifier_verify_memberref_field_signature(MonoImage * image,guint32 offset,GSList ** error_list)4157 mono_verifier_verify_memberref_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4158 {
4159 VerifyContext ctx;
4160
4161 if (!mono_verifier_is_enabled_for_image (image))
4162 return TRUE;
4163
4164 init_verify_context (&ctx, image, error_list != NULL);
4165 ctx.stage = STAGE_TABLES;
4166
4167 is_valid_field_signature (&ctx, offset);
4168 return cleanup_context (&ctx, error_list);
4169 }
4170
4171 gboolean
mono_verifier_verify_standalone_signature(MonoImage * image,guint32 offset,GSList ** error_list)4172 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
4173 {
4174 VerifyContext ctx;
4175
4176 if (!mono_verifier_is_enabled_for_image (image))
4177 return TRUE;
4178
4179 init_verify_context (&ctx, image, error_list != NULL);
4180 ctx.stage = STAGE_TABLES;
4181
4182 is_valid_standalonesig_blob (&ctx, offset);
4183 return cleanup_context (&ctx, error_list);
4184 }
4185
4186 gboolean
mono_verifier_verify_typespec_signature(MonoImage * image,guint32 offset,guint32 token,GSList ** error_list)4187 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
4188 {
4189 VerifyContext ctx;
4190
4191 if (!mono_verifier_is_enabled_for_image (image))
4192 return TRUE;
4193
4194 init_verify_context (&ctx, image, error_list != NULL);
4195 ctx.stage = STAGE_TABLES;
4196 ctx.token = token;
4197
4198 is_valid_typespec_blob (&ctx, offset);
4199 return cleanup_context (&ctx, error_list);
4200 }
4201
4202 gboolean
mono_verifier_verify_methodspec_signature(MonoImage * image,guint32 offset,GSList ** error_list)4203 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
4204 {
4205 VerifyContext ctx;
4206
4207 if (!mono_verifier_is_enabled_for_image (image))
4208 return TRUE;
4209
4210 init_verify_context (&ctx, image, error_list != NULL);
4211 ctx.stage = STAGE_TABLES;
4212
4213 is_valid_methodspec_blob (&ctx, offset);
4214 return cleanup_context (&ctx, error_list);
4215 }
4216
4217 static void
verify_user_string(VerifyContext * ctx,guint32 offset)4218 verify_user_string (VerifyContext *ctx, guint32 offset)
4219 {
4220 OffsetAndSize heap_us = get_metadata_stream (ctx, &ctx->image->heap_us);
4221 guint32 entry_size, bytes;
4222
4223 if (heap_us.size < offset)
4224 ADD_ERROR (ctx, g_strdup ("User string offset beyond heap_us size"));
4225
4226 if (!decode_value (ctx->data + offset + heap_us.offset, heap_us.size - heap_us.offset, &entry_size, &bytes))
4227 ADD_ERROR (ctx, g_strdup ("Could not decode user string blob size"));
4228
4229 if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
4230 ADD_ERROR (ctx, g_strdup ("User string size overflow"));
4231
4232 entry_size += bytes;
4233
4234 if (ADD_IS_GREATER_OR_OVF (offset, entry_size, heap_us.size))
4235 ADD_ERROR (ctx, g_strdup ("User string oveflow heap_us"));
4236 }
4237
4238 gboolean
mono_verifier_verify_string_signature(MonoImage * image,guint32 offset,GSList ** error_list)4239 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
4240 {
4241 VerifyContext ctx;
4242
4243 if (!mono_verifier_is_enabled_for_image (image))
4244 return TRUE;
4245
4246 init_verify_context (&ctx, image, error_list != NULL);
4247 ctx.stage = STAGE_TABLES;
4248
4249 verify_user_string (&ctx, offset);
4250
4251 return cleanup_context (&ctx, error_list);
4252 }
4253
4254 gboolean
mono_verifier_verify_cattr_blob(MonoImage * image,guint32 offset,GSList ** error_list)4255 mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, GSList **error_list)
4256 {
4257 VerifyContext ctx;
4258
4259 if (!mono_verifier_is_enabled_for_image (image))
4260 return TRUE;
4261
4262 init_verify_context (&ctx, image, error_list != NULL);
4263 ctx.stage = STAGE_TABLES;
4264
4265 is_valid_cattr_blob (&ctx, offset);
4266
4267 return cleanup_context (&ctx, error_list);
4268 }
4269
4270 gboolean
mono_verifier_verify_cattr_content(MonoImage * image,MonoMethod * ctor,const guchar * data,guint32 size,GSList ** error_list)4271 mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, GSList **error_list)
4272 {
4273 VerifyContext ctx;
4274
4275 if (!mono_verifier_is_enabled_for_image (image))
4276 return TRUE;
4277
4278 init_verify_context (&ctx, image, error_list != NULL);
4279 ctx.stage = STAGE_TABLES;
4280
4281 is_valid_cattr_content (&ctx, ctor, (const char*)data, size);
4282
4283 return cleanup_context (&ctx, error_list);
4284 }
4285
4286 gboolean
mono_verifier_is_sig_compatible(MonoImage * image,MonoMethod * method,MonoMethodSignature * signature)4287 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
4288 {
4289 MonoMethodSignature *original_sig;
4290 if (!mono_verifier_is_enabled_for_image (image))
4291 return TRUE;
4292
4293 original_sig = mono_method_signature (method);
4294 if (original_sig->call_convention == MONO_CALL_VARARG) {
4295 if (original_sig->hasthis != signature->hasthis)
4296 return FALSE;
4297 if (original_sig->call_convention != signature->call_convention)
4298 return FALSE;
4299 if (original_sig->explicit_this != signature->explicit_this)
4300 return FALSE;
4301 if (original_sig->pinvoke != signature->pinvoke)
4302 return FALSE;
4303 if (original_sig->sentinelpos != signature->sentinelpos)
4304 return FALSE;
4305 } else if (!mono_metadata_signature_equal (signature, original_sig)) {
4306 return FALSE;
4307 }
4308
4309 return TRUE;
4310 }
4311
4312 gboolean
mono_verifier_verify_typeref_row(MonoImage * image,guint32 row,MonoError * error)4313 mono_verifier_verify_typeref_row (MonoImage *image, guint32 row, MonoError *error)
4314 {
4315 MonoTableInfo *table = &image->tables [MONO_TABLE_TYPEREF];
4316 guint32 data [MONO_TYPEREF_SIZE];
4317
4318 error_init (error);
4319
4320 if (!mono_verifier_is_enabled_for_image (image))
4321 return TRUE;
4322
4323 if (row >= table->rows) {
4324 mono_error_set_bad_image (error, image, "Invalid typeref row %d - table has %d rows", row, table->rows);
4325 return FALSE;
4326 }
4327
4328 mono_metadata_decode_row (table, row, data, MONO_TYPEREF_SIZE);
4329 if (!is_valid_coded_index_with_image (image, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE])) {
4330 mono_error_set_bad_image (error, image, "Invalid typeref row %d coded index 0x%08x", row, data [MONO_TYPEREF_SCOPE]);
4331 return FALSE;
4332 }
4333
4334 if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE])) {
4335 mono_error_set_bad_image (error, image, "The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", row);
4336 return FALSE;
4337 }
4338
4339 if (!data [MONO_TYPEREF_NAME] || !is_valid_string_full_with_image (image, data [MONO_TYPEREF_NAME], FALSE)) {
4340 mono_error_set_bad_image (error, image, "Invalid typeref row %d name token 0x%08x", row, data [MONO_TYPEREF_NAME]);
4341 return FALSE;
4342 }
4343
4344 if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_string_full_with_image (image, data [MONO_TYPEREF_NAMESPACE], FALSE)) {
4345 mono_error_set_bad_image (error, image, "Invalid typeref row %d namespace token 0x%08x", row, data [MONO_TYPEREF_NAMESPACE]);
4346 return FALSE;
4347 }
4348
4349 return TRUE;
4350 }
4351
4352 /*Perform additional verification including metadata ones*/
4353 gboolean
mono_verifier_verify_methodimpl_row(MonoImage * image,guint32 row,MonoError * error)4354 mono_verifier_verify_methodimpl_row (MonoImage *image, guint32 row, MonoError *error)
4355 {
4356 MonoMethod *declaration, *body;
4357 MonoMethodSignature *body_sig, *decl_sig;
4358 MonoTableInfo *table = &image->tables [MONO_TABLE_METHODIMPL];
4359 guint32 data [MONO_METHODIMPL_SIZE];
4360
4361 error_init (error);
4362
4363 if (!mono_verifier_is_enabled_for_image (image))
4364 return TRUE;
4365
4366 if (row >= table->rows) {
4367 mono_error_set_bad_image (error, image, "Invalid methodimpl row %d - table has %d rows", row, table->rows);
4368 return FALSE;
4369 }
4370
4371 mono_metadata_decode_row (table, row, data, MONO_METHODIMPL_SIZE);
4372
4373 body = method_from_method_def_or_ref (image, data [MONO_METHODIMPL_BODY], NULL, error);
4374 if (!body)
4375 return FALSE;
4376
4377 declaration = method_from_method_def_or_ref (image, data [MONO_METHODIMPL_DECLARATION], NULL, error);
4378 if (!declaration)
4379 return FALSE;
4380
4381 /* FIXME
4382 mono_class_setup_supertypes (class);
4383 if (!mono_class_has_parent (class, body->klass)) {
4384 mono_error_set_bad_image (error, image, "Invalid methodimpl body doesn't belong to parent for row %x", row);
4385 return FALSE;
4386 }*/
4387
4388 if (!(body_sig = mono_method_signature_checked (body, error))) {
4389 return FALSE;
4390 }
4391
4392 if (!(decl_sig = mono_method_signature_checked (declaration, error))) {
4393 return FALSE;
4394 }
4395
4396 if (!mono_verifier_is_signature_compatible (decl_sig, body_sig)) {
4397 mono_error_set_bad_image (error, image, "Invalid methodimpl body signature not compatible with declaration row %x", row);
4398 return FALSE;
4399 }
4400
4401 return TRUE;
4402 }
4403
4404 #else
4405 gboolean
mono_verifier_verify_table_data(MonoImage * image,GSList ** error_list)4406 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
4407 {
4408 return TRUE;
4409 }
4410
4411 gboolean
mono_verifier_verify_cli_data(MonoImage * image,GSList ** error_list)4412 mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
4413 {
4414 return TRUE;
4415 }
4416
4417 gboolean
mono_verifier_verify_pe_data(MonoImage * image,GSList ** error_list)4418 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
4419 {
4420 return TRUE;
4421 }
4422
4423 gboolean
mono_verifier_verify_full_table_data(MonoImage * image,GSList ** error_list)4424 mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
4425 {
4426 return TRUE;
4427 }
4428
4429 gboolean
mono_verifier_verify_field_signature(MonoImage * image,guint32 offset,GSList ** error_list)4430 mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4431 {
4432 return TRUE;
4433 }
4434
4435 gboolean
mono_verifier_verify_method_header(MonoImage * image,guint32 offset,GSList ** error_list)4436 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
4437 {
4438 return TRUE;
4439 }
4440
4441 gboolean
mono_verifier_verify_method_signature(MonoImage * image,guint32 offset,MonoError * error)4442 mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, MonoError *error)
4443 {
4444 error_init (error);
4445 return TRUE;
4446 }
4447
4448 gboolean
mono_verifier_verify_standalone_signature(MonoImage * image,guint32 offset,GSList ** error_list)4449 mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
4450 {
4451 return TRUE;
4452 }
4453
4454 gboolean
mono_verifier_verify_typespec_signature(MonoImage * image,guint32 offset,guint32 token,GSList ** error_list)4455 mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
4456 {
4457 return TRUE;
4458 }
4459
4460 gboolean
mono_verifier_verify_methodspec_signature(MonoImage * image,guint32 offset,GSList ** error_list)4461 mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
4462 {
4463 return TRUE;
4464 }
4465
4466 gboolean
mono_verifier_verify_string_signature(MonoImage * image,guint32 offset,GSList ** error_list)4467 mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
4468 {
4469 return TRUE;
4470 }
4471
4472 gboolean
mono_verifier_verify_cattr_blob(MonoImage * image,guint32 offset,GSList ** error_list)4473 mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, GSList **error_list)
4474 {
4475 return TRUE;
4476 }
4477
4478 gboolean
mono_verifier_verify_cattr_content(MonoImage * image,MonoMethod * ctor,const guchar * data,guint32 size,GSList ** error_list)4479 mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, GSList **error_list)
4480 {
4481 return TRUE;
4482 }
4483
4484 gboolean
mono_verifier_is_sig_compatible(MonoImage * image,MonoMethod * method,MonoMethodSignature * signature)4485 mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
4486 {
4487 return TRUE;
4488 }
4489
4490
4491 gboolean
mono_verifier_verify_typeref_row(MonoImage * image,guint32 row,MonoError * error)4492 mono_verifier_verify_typeref_row (MonoImage *image, guint32 row, MonoError *error)
4493 {
4494 error_init (error);
4495 return TRUE;
4496 }
4497
4498 gboolean
mono_verifier_verify_methodimpl_row(MonoImage * image,guint32 row,MonoError * error)4499 mono_verifier_verify_methodimpl_row (MonoImage *image, guint32 row, MonoError *error)
4500 {
4501 error_init (error);
4502 return TRUE;
4503 }
4504
4505 gboolean
mono_verifier_verify_memberref_method_signature(MonoImage * image,guint32 offset,GSList ** error_list)4506 mono_verifier_verify_memberref_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
4507 {
4508 return TRUE;
4509 }
4510
4511 gboolean
mono_verifier_verify_memberref_field_signature(MonoImage * image,guint32 offset,GSList ** error_list)4512 mono_verifier_verify_memberref_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
4513 {
4514 return TRUE;
4515 }
4516
4517 #endif /* DISABLE_VERIFIER */
4518