2009-01-14 Rodrigo Kumpera <rkumpera@novell.com>
authorRodrigo Kumpera <kumpera@gmail.com>
Thu, 15 Jan 2009 00:23:40 +0000 (00:23 -0000)
committerRodrigo Kumpera <kumpera@gmail.com>
Thu, 15 Jan 2009 00:23:40 +0000 (00:23 -0000)
* metadata-verify.c: Add pe optional header verification.

svn path=/trunk/mono/; revision=123441

mono/metadata/ChangeLog
mono/metadata/metadata-verify.c

index 2011842bb81a8fbee7e0c5345c799bc011ac5447..aa4b3ba9ef4ef77c51d5ec9e1722dcf1004e4c53 100644 (file)
@@ -1,3 +1,7 @@
+2009-01-14 Rodrigo Kumpera  <rkumpera@novell.com>
+
+       * metadata-verify.c: Add pe optional header verification.
+
 2009-01-15  Zoltan Varga  <vargaz@gmail.com>
 
        * sgen-gc.c: Add support for user defined marker functions, used by
index 8b959659c6d7b25a4fc5b5f640fc278d55def70c..3d106182c6b6d9a28447d32a7a03e2169abf56bd 100644 (file)
 #include <signal.h>
 #include <ctype.h>
 
+/*
+ TODO add fail fast mode
+ TODO add PE32+ support
+*/
+
 typedef struct {
        const char *data;
        guint32 size;
@@ -39,6 +44,12 @@ typedef struct {
 
 #define CHECK_STATE() do { if (!ctx.valid) goto cleanup; } while (0)
 
+static guint32
+pe_signature_offset (VerifyContext *ctx)
+{
+       return read32 (ctx->data + 0x3c);
+}
+
 static void
 verify_msdos_header (VerifyContext *ctx)
 {
@@ -49,7 +60,7 @@ verify_msdos_header (VerifyContext *ctx)
        }
        if (ctx->data [0] != 0x4d || ctx->data [1] != 0x5a)
                ADD_ERROR (ctx,  g_strdup ("Invalid MS-DOS watermark"));
-       lfanew = read32 (ctx->data + 0x3c);
+       lfanew = pe_signature_offset (ctx);
        if (lfanew > ctx->size - 4)
                ADD_ERROR (ctx, g_strdup ("MS-DOS lfanew offset points to outside of the file"));
 }
@@ -57,7 +68,7 @@ verify_msdos_header (VerifyContext *ctx)
 static void
 verify_pe_header (VerifyContext *ctx)
 {
-       guint32 offset = read32 (ctx->data + 0x3c);
+       guint32 offset = pe_signature_offset (ctx);
        const char *pe_header = ctx->data + offset;
        if (pe_header [0] != 'P' || pe_header [1] != 'E' ||pe_header [2] != 0 ||pe_header [3] != 0)
                ADD_ERROR (ctx,  g_strdup ("Invalid PE header watermark"));
@@ -71,6 +82,33 @@ verify_pe_header (VerifyContext *ctx)
 
 }
 
+static void
+verify_pe_optional_header (VerifyContext *ctx)
+{
+       guint32 offset = pe_signature_offset (ctx) + 4;
+       guint32 header_size;
+       const char *pe_header = ctx->data + offset;
+       const char *pe_optional_header = pe_header + 20;
+
+       header_size = read16 (pe_header + 16);
+       offset += 20;
+
+       if (header_size < 2) /*must be at least 2 or we won't be able to read magic*/
+               ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
+
+       if (offset > ctx->size - header_size || header_size > ctx->size)
+               ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
+
+       if (read16 (pe_optional_header) == 0x10b) {
+               if (header_size != 224)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header size %d", header_size));
+       } else {
+               if (read16 (pe_optional_header) == 0x20B)
+                       ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle PE32+"));
+               else
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header magic %d", read16 (pe_optional_header)));
+       }
+}
 
 GSList*
 mono_image_verify (const char *data, guint32 size)
@@ -85,6 +123,8 @@ mono_image_verify (const char *data, guint32 size)
        CHECK_STATE();
        verify_pe_header (&ctx);
        CHECK_STATE();
+       verify_pe_optional_header (&ctx);
+       CHECK_STATE();
 
 cleanup:
        return ctx.errors;