Skip to content

Commit 03751d5

Browse files
authored
Merge pull request #1324 from Unity-Technologies/unity-master-update-pe-verifier
Unity master update pe verifier
2 parents d9814ea + 4b1f6fc commit 03751d5

File tree

4 files changed

+81
-48
lines changed

4 files changed

+81
-48
lines changed

mono/metadata/image.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1345,7 +1345,10 @@ do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status,
13451345
invalid_image:
13461346
if (errors) {
13471347
MonoVerifyInfo *info = (MonoVerifyInfo *)errors->data;
1348-
g_warning ("Could not load image %s due to %s", image->name, info->message);
1348+
char* log_message = g_strdup_printf("Could not load image %s due to %s\nRun the peverify utility against this for more information.", image->name, info->message);
1349+
if (!mono_unity_log_error_to_editor(log_message))
1350+
g_warning (log_message);
1351+
g_free(log_message);
13491352
mono_free_verify_list (errors);
13501353
}
13511354
MONO_PROFILER_RAISE (image_failed, (image));

mono/metadata/metadata-verify.c

Lines changed: 56 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,7 @@
3636
#ifndef DISABLE_VERIFIER
3737
/*
3838
TODO add fail fast mode
39-
TODO add PE32+ support
4039
TODO verify the entry point RVA and content.
41-
TODO load_section_table and load_data_directories must take PE32+ into account
4240
TODO add section relocation support
4341
TODO verify the relocation table, since we really don't use, no need so far.
4442
TODO do full PECOFF resources verification
@@ -231,9 +229,11 @@ typedef struct {
231229
gboolean report_warning;
232230
int stage;
233231

232+
// Mono really only requires 15 here, but verifies the extra is zeroed.
234233
DataDirectory data_directories [16];
235234
guint32 section_count;
236235
SectionHeader *sections;
236+
guint pe64; // short name for PE32+; actual PE64 proposal was rejected
237237

238238
OffsetAndSize metadata_streams [5]; //offset from begin of the image
239239
} VerifyContext;
@@ -441,8 +441,6 @@ verify_pe_header (VerifyContext *ctx)
441441

442442
if (offset > ctx->size - 20)
443443
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"));
446444
}
447445

448446
static void
@@ -462,40 +460,58 @@ verify_pe_optional_header (VerifyContext *ctx)
462460
if (offset > ctx->size - header_size || header_size > ctx->size)
463461
ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
464462

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-
}
463+
const guint16 magic = read16 (pe_optional_header);
464+
465+
if (magic == 0x20B) {
466+
// Some fields are the same location for PE32 and PE32+.
467+
// A few are offset by 4, 8, or 12, but we do not use them.
468+
// Others are offset by 16.
469+
// Some are missing.
470+
ctx->pe64 = 16;
471+
} else if (magic != 0x10b)
472+
ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header magic %d", magic));
473+
474+
// Much of this is over-verification.
475+
//
476+
// File align and section align do not matter to Mono.
477+
//
478+
// Mono requires at least 15 data directories. More than that are ignored,
479+
// except to require zeros in the 16th.
480+
//
481+
// Mono requires at least 216 (or pe64:232) size.
482+
483+
/* LAMESPEC MS plays around this value and ignore it during validation
484+
if (read32 (pe_optional_header + 28) != 0x400000)
485+
ADD_ERROR (ctx, g_strdup_printf ("Invalid Image base %x", read32 (pe_optional_header + 28)));*/
486+
if (read32 (pe_optional_header + 32) != 0x2000)
487+
ADD_ERROR (ctx, g_strdup_printf ("Invalid Section Aligmnent %x", read32 (pe_optional_header + 32)));
488+
file_alignment = read32 (pe_optional_header + 36);
489+
if (file_alignment != 0x200 && file_alignment != 0x1000)
490+
ADD_ERROR (ctx, g_strdup_printf ("Invalid file Aligmnent %x", file_alignment));
491+
/* All the junk in the middle is irrelevant, specially for mono. */
492+
493+
if (header_size != 224 + ctx->pe64)
494+
ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header size %d", header_size));
495+
496+
const guint number_of_rvas_and_sizes = read32 (pe_optional_header + 92 + ctx->pe64);
497+
498+
// Data directories beyond 15 do not matter to mono.
499+
if (number_of_rvas_and_sizes > 0x10)
500+
ADD_ERROR (ctx, g_strdup_printf ("Too many data directories %x", number_of_rvas_and_sizes));
486501
}
487502

488503
static void
489504
load_section_table (VerifyContext *ctx)
490505
{
491506
int i;
492507
SectionHeader *sections;
493-
guint32 offset = pe_header_offset (ctx);
508+
guint32 offset = pe_header_offset (ctx);
494509
const char *ptr = ctx->data + offset;
495510
guint16 num_sections = ctx->section_count = read16 (ptr + 2);
496511

497-
offset += 244;/*FIXME, this constant is different under PE32+*/
498-
ptr += 244;
512+
const guint optional_header_size = read16 (ptr + 16);
513+
offset += optional_header_size + 20;
514+
ptr += optional_header_size + 20;
499515

500516
if (num_sections * 40 > ctx->size - offset)
501517
ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
@@ -549,19 +565,18 @@ is_valid_data_directory (int i)
549565
static void
550566
load_data_directories (VerifyContext *ctx)
551567
{
552-
guint32 offset = pe_header_offset (ctx) + 116; /*FIXME, this constant is different under PE32+*/
568+
guint32 offset = pe_header_offset (ctx) + 116 + ctx->pe64;
553569
const char *ptr = ctx->data + offset;
554570
int i;
555571

556-
for (i = 0; i < 16; ++i) {
572+
for (i = 0; i < 16; ++i, ptr += 8) {
557573
guint32 rva = read32 (ptr);
558574
guint32 size = read32 (ptr + 4);
559575

560576
/*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;
577+
if (i == CERTIFICATE_TABLE_IDX)
563578
continue;
564-
}
579+
565580
if ((rva != 0 || size != 0) && !is_valid_data_directory (i))
566581
ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d", i));
567582

@@ -571,8 +586,6 @@ load_data_directories (VerifyContext *ctx)
571586
ctx->data_directories [i].rva = rva;
572587
ctx->data_directories [i].size = size;
573588
ctx->data_directories [i].translated_offset = translate_rva (ctx, rva);
574-
575-
ptr += 8;
576589
}
577590
}
578591

@@ -597,12 +610,8 @@ verify_hint_name_table (VerifyContext *ctx, guint32 import_rva, const char *tabl
597610
g_assert (hint_table_rva != INVALID_OFFSET);
598611
ptr = ctx->data + hint_table_rva + 2;
599612

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-
}
613+
if (memcmp ("_CorExeMain", ptr, SIZE_OF_CORMAIN) && memcmp ("_CorDllMain", ptr, SIZE_OF_CORMAIN))
614+
ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint / Name: '%s'", ptr));
606615
}
607616

608617
static void
@@ -613,6 +622,10 @@ verify_import_table (VerifyContext *ctx)
613622
const char *ptr = ctx->data + offset;
614623
guint32 name_rva, ilt_rva, iat_rva;
615624

625+
// Having no import table is structurally valid
626+
if (it.rva == 0 && it.size == 0)
627+
return;
628+
616629
g_assert (offset != INVALID_OFFSET);
617630

618631
if (it.size < 40)
@@ -640,12 +653,8 @@ verify_import_table (VerifyContext *ctx)
640653
g_assert (name_rva != INVALID_OFFSET);
641654
ptr = ctx->data + name_rva;
642655

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-
}
656+
if (memcmp ("mscoree.dll", ptr, SIZE_OF_MSCOREE))
657+
ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name: '%s'", ptr));
649658
}
650659

651660
if (ilt_rva) {

mono/metadata/unity-utils.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -976,6 +976,23 @@ MONO_API int mono_unity_gc_is_disabled()
976976
#endif
977977
}
978978

979+
// Logging
980+
static UnityLogErrorCallback editorLoggingCallback;
981+
MONO_API void mono_unity_set_editor_logging_callback(UnityLogErrorCallback callback)
982+
{
983+
editorLoggingCallback = callback;
984+
}
985+
986+
gboolean mono_unity_log_error_to_editor(const char *message)
987+
{
988+
if (editorLoggingCallback)
989+
{
990+
editorLoggingCallback(message);
991+
return TRUE;
992+
}
993+
return FALSE;
994+
}
995+
979996
MONO_API void
980997
mono_unity_install_unitytls_interface(unitytls_interface_struct* callbacks)
981998
{

mono/metadata/unity-utils.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,10 @@ MONO_API void mono_unity_gc_disable();
169169
// Deprecated. Remove when Unity has switched to mono_unity_gc_set_mode
170170
MONO_API int mono_unity_gc_is_disabled();
171171

172+
// logging
173+
typedef void (*UnityLogErrorCallback) (const char *message);
174+
MONO_API void mono_unity_set_editor_logging_callback(UnityLogErrorCallback callback);
175+
gboolean mono_unity_log_error_to_editor(const char *message);
172176

173177
//misc
174178
MonoAssembly* mono_unity_assembly_get_mscorlib();

0 commit comments

Comments
 (0)