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, &current_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, &current_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