#include <mono/metadata/cil-coff.h>
#include <mono/metadata/attrdefs.h>
#include <mono/utils/strenc.h>
+#include <mono/utils/mono-error-internals.h>
#include <string.h>
//#include <signal.h>
#include <ctype.h>
#define HAS_CATTR_DESC (HAS_CONSTANT_DESC + 5)
5, /*bits*/
- 19, /*tables*/
+ 20, /*tables*/
MONO_TABLE_METHOD,
MONO_TABLE_FIELD,
MONO_TABLE_TYPEREF,
MONO_TABLE_FILE,
MONO_TABLE_EXPORTEDTYPE,
MONO_TABLE_MANIFESTRESOURCE,
+ MONO_TABLE_GENERICPARAM,
-#define HAS_FIELD_MARSHAL_DESC (HAS_CATTR_DESC + 21)
+#define HAS_FIELD_MARSHAL_DESC (HAS_CATTR_DESC + 22)
1, /*bits*/
2, /*tables*/
MONO_TABLE_FIELD,
typedef struct {
const char *data;
- guint32 size;
+ guint32 size, token;
GSList *errors;
int valid;
MonoImage *image;
gboolean report_error;
+ gboolean report_warning;
int stage;
DataDirectory data_directories [16];
(__ctx)->errors = g_slist_prepend ((__ctx)->errors, vinfo); \
} while (0)
+#define ADD_WARNING(__ctx, __msg) \
+ do { \
+ if ((__ctx)->report_warning) { \
+ ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_WARNING, MONO_EXCEPTION_INVALID_PROGRAM); \
+ (__ctx)->valid = 0; \
+ return; \
+ } \
+ } while (0)
+
+#define ADD_ERROR_NO_RETURN(__ctx, __msg) \
+ do { \
+ if ((__ctx)->report_error) \
+ ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
+ (__ctx)->valid = 0; \
+ } while (0)
#define ADD_ERROR(__ctx, __msg) \
do { \
{
int i;
DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
- guint32 offset;
+ guint32 offset, section_count;
const char *ptr;
offset = it.translated_offset;
ptr = ctx->data + offset; //move to streams header
- if (read16 (ptr + 2) < 3)
- ADD_ERROR (ctx, g_strdup_printf ("Metadata root section must have at least 3 streams (#~, #GUID and #Blob"));
+ section_count = read16 (ptr + 2);
+ if (section_count < 2)
+ ADD_ERROR (ctx, g_strdup_printf ("Metadata root section must have at least 2 streams (#~ and #GUID)"));
ptr += 4;
offset += 4;
- for (i = 0; i < 5; ++i) {
+ for (i = 0; i < section_count; ++i) {
guint32 stream_off, stream_size;
int string_size, stream_idx;
stream_idx = GUID_STREAM;
else if (!strncmp ("#~", ptr, 3))
stream_idx = TILDE_STREAM;
- else
- ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d invalid name %s", i, ptr));
+ else {
+ ADD_WARNING (ctx, g_strdup_printf ("Metadata stream header %d invalid name %s", i, ptr));
+ offset = pad4 (offset);
+ ptr = ctx->data + offset;
+ continue;
+ }
if (ctx->metadata_streams [stream_idx].offset != 0)
ADD_ERROR (ctx, g_strdup_printf ("Duplicated metadata stream header %s", ptr));
ADD_ERROR (ctx, g_strdup_printf ("Metadata #~ stream missing"));
if (!ctx->metadata_streams [GUID_STREAM].size)
ADD_ERROR (ctx, g_strdup_printf ("Metadata guid stream missing"));
- if (!ctx->metadata_streams [BLOB_STREAM].size)
- ADD_ERROR (ctx, g_strdup_printf ("Metadata blob stream missing"));
-
}
static void
guint32 count;
int i;
- //printf ("tables_area size %d offset %x %s\n", tables_area.size, tables_area.offset, ctx->image->name);
if (tables_area.size < 24)
ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for initial decoding (requires 24 bytes)", tables_area.size));
- //printf ("ptr %x %x\n", ptr[4], ptr[5]);
if (ptr [4] != 2 && ptr [4] != 1)
ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata major version %d, expected 2", ptr [4]));
if (ptr [5] != 0)
Unused: 0x1E 0x1F 0x2D-0x3F
We don't care about the MS extensions.*/
if (i == 0x3 || i == 0x5 || i == 0x7 || i == 0x13 || i == 0x16)
- ADD_ERROR (ctx, g_strdup_printf ("The metadata verifies doesn't support MS specific table %x", i));
+ ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support MS specific table %x", i));
if (i == 0x1E || i == 0x1F || i >= 0x2D)
ADD_ERROR (ctx, g_strdup_printf ("Invalid table %x", i));
++count;
}
static gboolean
-decode_signature_header (VerifyContext *ctx, guint32 offset, int *size, const char **first_byte)
+decode_signature_header (VerifyContext *ctx, guint32 offset, guint32 *size, const char **first_byte)
{
MonoStreamHeader blob = ctx->image->heap_blob;
guint32 value, enc_size;
if (!decode_value (blob.data + offset, blob.size - offset, &value, &enc_size))
return FALSE;
- if (offset + enc_size + value < offset)
+ if (CHECK_ADD4_OVERFLOW_UN (offset, enc_size))
return FALSE;
- if (offset + enc_size + value > blob.size)
+ offset += enc_size;
+
+ if (ADD_IS_GREATER_OR_OVF (offset, value, blob.size))
return FALSE;
*size = value;
- *first_byte = blob.data + offset + enc_size;
+ *first_byte = blob.data + offset;
return TRUE;
}
static gboolean
-safe_read (const char **_ptr, const char *limit, void *dest, int size)
+safe_read (const char **_ptr, const char *limit, unsigned *dest, int size)
{
const char *ptr = *_ptr;
if (ptr + size > limit)
return FALSE;
switch (size) {
case 1:
- *((guint8*)dest) = *((guint8*)ptr);
+ *dest = *((guint8*)ptr);
++ptr;
break;
case 2:
- *((guint16*)dest) = read16 (ptr);
+ *dest = read16 (ptr);
ptr += 2;
break;
case 4:
- *((guint32*)dest) = read32 (ptr);
+ *dest = read32 (ptr);
ptr += 4;
break;
}
parse_custom_mods (VerifyContext *ctx, const char **_ptr, const char *end)
{
const char *ptr = *_ptr;
- guint type = 0;
- guint32 token = 0;
+ unsigned type = 0;
+ unsigned token = 0;
while (TRUE) {
if (!safe_read8 (type, ptr, end))
parse_array_shape (VerifyContext *ctx, const char **_ptr, const char *end)
{
const char *ptr = *_ptr;
- guint8 val;
- guint32 size, num, i;
+ unsigned val = 0;
+ unsigned size, num, i;
if (!safe_read8 (val, ptr, end))
FAIL (ctx, g_strdup ("ArrayShape: Not enough room for Rank"));
parse_generic_inst (VerifyContext *ctx, const char **_ptr, const char *end)
{
const char *ptr = *_ptr;
- guint8 type;
- guint32 count, token, i;
+ unsigned type;
+ unsigned count, token, i;
if (!safe_read8 (type, ptr, end))
FAIL (ctx, g_strdup ("GenericInst: Not enough room for kind"));
if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
FAIL (ctx, g_strdup_printf ("GenericInst: invalid TypeDefOrRef token %x", token));
+ if (ctx->token) {
+ if (mono_metadata_token_index (ctx->token) == get_coded_index_token (TYPEDEF_OR_REF_DESC, token) &&
+ mono_metadata_token_table (ctx->token) == get_coded_index_table (TYPEDEF_OR_REF_DESC, token))
+ FAIL (ctx, g_strdup_printf ("Type: Recurside generic instance specification (%x). A type signature can't reference itself", ctx->token));
+ }
+
if (!safe_read_cint (count, ptr, end))
FAIL (ctx, g_strdup ("GenericInst: Not enough room for argument count"));
parse_type (VerifyContext *ctx, const char **_ptr, const char *end)
{
const char *ptr = *_ptr;
- guint8 type = 0;
- guint32 token = 0;
+ unsigned type;
+ unsigned token = 0;
if (!safe_read8 (type, ptr, end))
FAIL (ctx, g_strdup ("Type: Not enough room for the type"));
if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
FAIL (ctx, g_strdup_printf ("Type: invalid TypeDefOrRef token %x", token));
+ if (ctx->token) {
+ if (mono_metadata_token_index (ctx->token) == get_coded_index_token (TYPEDEF_OR_REF_DESC, token) &&
+ mono_metadata_token_table (ctx->token) == get_coded_index_table (TYPEDEF_OR_REF_DESC, token))
+ FAIL (ctx, g_strdup_printf ("Type: Recurside type specification (%x). A type signature can't reference itself", ctx->token));
+ }
break;
case MONO_TYPE_VAR:
parse_return_type (VerifyContext *ctx, const char **_ptr, const char *end)
{
const char *ptr;
- int type = 0;
+ unsigned type = 0;
if (!parse_custom_mods (ctx, _ptr, end))
return FALSE;
parse_param (VerifyContext *ctx, const char **_ptr, const char *end)
{
const char *ptr;
- int type = 0;
+ unsigned type = 0;
if (!parse_custom_mods (ctx, _ptr, end))
return FALSE;
static gboolean
parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged)
{
- int cconv = 0;
+ unsigned cconv = 0;
unsigned param_count = 0, gparam_count = 0, type = 0, i;
const char *ptr = *_ptr;
gboolean saw_sentinel = FALSE;
parse_field (VerifyContext *ctx, const char **_ptr, const char *end)
{
const char *ptr = *_ptr;
- guint8 signature = 0;
+ unsigned signature = 0;
if (!safe_read8 (signature, ptr, end))
FAIL (ctx, g_strdup ("Field: Not enough room for field signature"));
if (signature != 0x06)
FAIL (ctx, g_strdup_printf ("Field: Invalid signature 0x%x, must be 6", signature));
- *_ptr = ptr;
- if (!parse_custom_mods (ctx, _ptr, end))
+ if (!parse_custom_mods (ctx, &ptr, end))
return FALSE;
+ if (safe_read8 (signature, ptr, end)) {
+ if (signature != MONO_TYPE_BYREF)
+ --ptr;
+ }
+ *_ptr = ptr;
+
return parse_type (ctx, _ptr, end);
}
if (!safe_read_cint (locals_count, ptr, end))
FAIL (ctx, g_strdup ("LocalsSig: Not enough room for the param count"));
+ /* LAMEIMPL: MS sometimes generates empty local signatures and its verifier is ok with.
if (locals_count == 0)
FAIL (ctx, g_strdup ("LocalsSig: Signature with zero locals"));
+ */
for (i = 0; i < locals_count; ++i) {
if (!safe_read8 (sig, ptr, end))
FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
- if (sig == MONO_TYPE_TYPEDBYREF)
- continue;
-
while (sig == MONO_TYPE_CMOD_REQD || sig == MONO_TYPE_CMOD_OPT || sig == MONO_TYPE_PINNED) {
if (sig != MONO_TYPE_PINNED && !parse_custom_mods (ctx, &ptr, end))
FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
if (!safe_read8 (sig, ptr, end))
FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
}
+
+ if (sig == MONO_TYPE_BYREF) {
+ if (!safe_read8 (sig, ptr, end))
+ FAIL (ctx, g_strdup_printf ("Type: Not enough room for byref type for local %d", i));
+ if (sig == MONO_TYPE_TYPEDBYREF)
+ FAIL (ctx, g_strdup_printf ("Type: Invalid type typedref& for local %d", i));
+ }
+
+ if (sig == MONO_TYPE_TYPEDBYREF)
+ continue;
+
--ptr;
+
if (!parse_type (ctx, &ptr, end))
FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
}
static gboolean
is_valid_field_signature (VerifyContext *ctx, guint32 offset)
{
- int size = 0, signature = 0;
+ guint32 size = 0;
+ unsigned signature = 0;
const char *ptr = NULL, *end;
if (!decode_signature_header (ctx, offset, &size, &ptr))
static gboolean
is_valid_method_signature (VerifyContext *ctx, guint32 offset)
{
- int size = 0;
+ guint32 size = 0;
const char *ptr = NULL, *end;
if (!decode_signature_header (ctx, offset, &size, &ptr))
static gboolean
is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
{
- int size = 0;
+ guint32 size = 0;
unsigned signature = 0;
const char *ptr = NULL, *end;
}
static gboolean
-is_vald_cattr_blob (VerifyContext *ctx, guint32 offset)
+is_valid_cattr_blob (VerifyContext *ctx, guint32 offset)
{
- int size = 0;
- guint16 prolog = 0;
+ guint32 size = 0;
+ unsigned prolog = 0;
const char *ptr = NULL, *end;
if (!offset)
if (prolog != 1)
FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
-
+
+ return TRUE;
+}
+
+static gboolean
+is_valid_cattr_type (MonoType *type)
+{
+ MonoClass *klass;
+
+ if (type->type == MONO_TYPE_OBJECT || (type->type >= MONO_TYPE_BOOLEAN && type->type <= MONO_TYPE_STRING))
+ return TRUE;
+
+ if (type->type == MONO_TYPE_VALUETYPE) {
+ klass = mono_class_from_mono_type (type);
+ return klass && klass->enumtype;
+ }
+
+ if (type->type == MONO_TYPE_CLASS)
+ return mono_class_from_mono_type (type) == mono_defaults.systemtype_class;
+
+ return FALSE;
+}
+
+static gboolean
+is_valid_ser_string_full (VerifyContext *ctx, const char **str_start, guint32 *str_len, const char **_ptr, const char *end)
+{
+ guint32 size = 0;
+ const char *ptr = *_ptr;
+
+ *str_start = NULL;
+ *str_len = 0;
+
+ if (ptr >= end)
+ FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string size"));
+
+ /*NULL string*/
+ if (*ptr == (char)0xFF) {
+ *_ptr = ptr + 1;
+ return TRUE;
+ }
+
+ if (!safe_read_cint (size, ptr, end))
+ FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string size"));
+
+ if (ADDP_IS_GREATER_OR_OVF (ptr, size, end))
+ FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string"));
+
+ *str_start = ptr;
+ *str_len = size;
+
+ *_ptr = ptr + size;
+ return TRUE;
+}
+
+static gboolean
+is_valid_ser_string (VerifyContext *ctx, const char **_ptr, const char *end)
+{
+ const char *dummy_str;
+ guint32 dummy_int;
+ return is_valid_ser_string_full (ctx, &dummy_str, &dummy_int, _ptr, end);
+}
+
+static MonoClass*
+get_enum_by_encoded_name (VerifyContext *ctx, const char **_ptr, const char *end)
+{
+ MonoType *type;
+ MonoClass *klass;
+ const char *str_start = NULL;
+ const char *ptr = *_ptr;
+ char *enum_name;
+ guint32 str_len = 0;
+
+ if (!is_valid_ser_string_full (ctx, &str_start, &str_len, &ptr, end))
+ return NULL;
+
+ /*NULL or empty string*/
+ if (str_start == NULL || str_len == 0) {
+ ADD_ERROR_NO_RETURN (ctx, g_strdup ("CustomAttribute: Null or empty enum name"));
+ return NULL;
+ }
+
+ enum_name = g_memdup (str_start, str_len + 1);
+ enum_name [str_len] = 0;
+ type = mono_reflection_type_from_name (enum_name, ctx->image);
+ if (!type) {
+ ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute: Invalid enum class %s", enum_name));
+ g_free (enum_name);
+ return NULL;
+ }
+ g_free (enum_name);
+
+ klass = mono_class_from_mono_type (type);
+ if (!klass || !klass->enumtype) {
+ ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute:Class %s::%s is not an enum", klass->name_space, klass->name));
+ return NULL;
+ }
+
+ *_ptr = ptr;
+ return klass;
+}
+
+static gboolean
+is_valid_fixed_param (VerifyContext *ctx, MonoType *mono_type, const char **_ptr, const char *end)
+{
+ MonoClass *klass;
+ const char *ptr = *_ptr;
+ int elem_size = 0;
+ guint32 element_count, i;
+ int type;
+
+ klass = mono_type->data.klass;
+ type = mono_type->type;
+
+handle_enum:
+ switch (type) {
+ case MONO_TYPE_BOOLEAN:
+ case MONO_TYPE_I1:
+ case MONO_TYPE_U1:
+ elem_size = 1;
+ break;
+ case MONO_TYPE_I2:
+ case MONO_TYPE_U2:
+ case MONO_TYPE_CHAR:
+ elem_size = 2;
+ break;
+ case MONO_TYPE_I4:
+ case MONO_TYPE_U4:
+ case MONO_TYPE_R4:
+ elem_size = 4;
+ break;
+ case MONO_TYPE_I8:
+ case MONO_TYPE_U8:
+ case MONO_TYPE_R8:
+ elem_size = 8;
+ break;
+
+ case MONO_TYPE_STRING:
+ *_ptr = ptr;
+ return is_valid_ser_string (ctx, _ptr, end);
+
+ case MONO_TYPE_OBJECT: {
+ unsigned sub_type = 0;
+ if (!safe_read8 (sub_type, ptr, end))
+ FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array type"));
+
+ if (sub_type >= MONO_TYPE_BOOLEAN && sub_type <= MONO_TYPE_STRING) {
+ type = sub_type;
+ goto handle_enum;
+ }
+ if (sub_type == MONO_TYPE_ENUM) {
+ klass = get_enum_by_encoded_name (ctx, &ptr, end);
+ if (!klass)
+ return FALSE;
+
+ klass = klass->element_class;
+ type = klass->byval_arg.type;
+ goto handle_enum;
+ }
+ if (sub_type == 0x50) { /*Type*/
+ *_ptr = ptr;
+ return is_valid_ser_string (ctx, _ptr, end);
+ }
+ if (sub_type == MONO_TYPE_SZARRAY) {
+ MonoType simple_type = {{0}};
+ unsigned etype = 0;
+ if (!safe_read8 (etype, ptr, end))
+ FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array element type"));
+
+ if (etype == MONO_TYPE_ENUM) {
+ klass = get_enum_by_encoded_name (ctx, &ptr, end);
+ if (!klass)
+ return FALSE;
+ } else if ((etype >= MONO_TYPE_BOOLEAN && etype <= MONO_TYPE_STRING) || etype == 0x51) {
+ simple_type.type = etype == 0x51 ? MONO_TYPE_OBJECT : etype;
+ klass = mono_class_from_mono_type (&simple_type);
+ } else
+ FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype));
+
+ type = MONO_TYPE_SZARRAY;
+ goto handle_enum;
+ }
+ FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid boxed object type %x", sub_type));
+ }
+
+
+ case MONO_TYPE_CLASS:
+ if (klass != mono_defaults.systemtype_class)
+ FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid class parameter type %s:%s ",klass->name_space, klass->name));
+ *_ptr = ptr;
+ return is_valid_ser_string (ctx, _ptr, end);
+
+ case MONO_TYPE_VALUETYPE:
+ if (!klass || !klass->enumtype)
+ FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid valuetype parameter expected enum %s:%s ",klass->name_space, klass->name));
+
+ klass = klass->element_class;
+ type = klass->byval_arg.type;
+ goto handle_enum;
+
+ case MONO_TYPE_SZARRAY:
+ mono_type = &klass->byval_arg;
+ if (!is_valid_cattr_type (mono_type))
+ FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %s:%s ",klass->name_space, klass->name));
+ if (!safe_read32 (element_count, ptr, end))
+ FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid class parameter type %s:%s ",klass->name_space, klass->name));
+ if (element_count == 0xFFFFFFFFu) {
+ *_ptr = ptr;
+ return TRUE;
+ }
+ for (i = 0; i < element_count; ++i) {
+ if (!is_valid_fixed_param (ctx, mono_type, &ptr, end))
+ return FALSE;
+ }
+ *_ptr = ptr;
+ return TRUE;
+ default:
+ FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid parameter type %x ", type));
+ }
+
+ if (ADDP_IS_GREATER_OR_OVF (ptr, elem_size, end))
+ FAIL (ctx, g_strdup ("CustomAttribute: Not enough space for element"));
+ *_ptr = ptr + elem_size;
+ return TRUE;
+}
+
+static gboolean
+is_valid_cattr_content (VerifyContext *ctx, MonoMethod *ctor, const char *ptr, guint32 size)
+{
+ MonoError error;
+ unsigned prolog = 0;
+ const char *end;
+ MonoMethodSignature *sig;
+ int args, i;
+ unsigned num_named;
+
+ if (!ctor)
+ FAIL (ctx, g_strdup ("CustomAttribute: Invalid constructor"));
+
+ sig = mono_method_signature_checked (ctor, &error);
+ if (!mono_error_ok (&error)) {
+ ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute: Invalid constructor signature %s", mono_error_get_message (&error)));
+ mono_error_cleanup (&error);
+ return FALSE;
+ }
+
+ if (sig->sentinelpos != -1 || sig->call_convention == MONO_CALL_VARARG)
+ FAIL (ctx, g_strdup ("CustomAttribute: Constructor cannot have VARAG signature"));
+
+ end = ptr + size;
+
+ if (!safe_read16 (prolog, ptr, end))
+ FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
+
+ if (prolog != 1)
+ FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
+
+ args = sig->param_count;
+ for (i = 0; i < args; ++i) {
+ MonoType *arg_type = sig->params [i];
+ if (!is_valid_fixed_param (ctx, arg_type, &ptr, end))
+ return FALSE;
+ }
+
+ if (!safe_read16 (num_named, ptr, end))
+ FAIL (ctx, g_strdup ("CustomAttribute: Not enough space for num_named field"));
+
+ for (i = 0; i < num_named; ++i) {
+ MonoType *type, simple_type = {{0}};
+ unsigned kind;
+
+ if (!safe_read8 (kind, ptr, end))
+ FAIL (ctx, g_strdup_printf ("CustomAttribute: Not enough space for named parameter %d kind", i));
+ if (kind != 0x53 && kind != 0x54)
+ FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid named parameter %d kind %x", i, kind));
+ if (!safe_read8 (kind, ptr, end))
+ FAIL (ctx, g_strdup_printf ("CustomAttribute: Not enough space for named parameter %d type", i));
+
+ if (kind >= MONO_TYPE_BOOLEAN && kind <= MONO_TYPE_STRING) {
+ simple_type.type = kind;
+ type = &simple_type;
+ } else if (kind == MONO_TYPE_ENUM) {
+ MonoClass *klass = get_enum_by_encoded_name (ctx, &ptr, end);
+ if (!klass)
+ return FALSE;
+ type = &klass->byval_arg;
+ } else if (kind == 0x50) {
+ type = &mono_defaults.systemtype_class->byval_arg;
+ } else if (kind == 0x51) {
+ type = &mono_defaults.object_class->byval_arg;
+ } else if (kind == MONO_TYPE_SZARRAY) {
+ MonoClass *klass;
+ unsigned etype = 0;
+ if (!safe_read8 (etype, ptr, end))
+ FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array element type"));
+
+ if (etype == MONO_TYPE_ENUM) {
+ klass = get_enum_by_encoded_name (ctx, &ptr, end);
+ if (!klass)
+ return FALSE;
+ } else if ((etype >= MONO_TYPE_BOOLEAN && etype <= MONO_TYPE_STRING) || etype == 0x51) {
+ simple_type.type = etype == 0x51 ? MONO_TYPE_OBJECT : etype;
+ klass = mono_class_from_mono_type (&simple_type);
+ } else
+ FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype));
+
+ type = &mono_array_class_get (klass, 1)->byval_arg;
+ } else {
+ FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid named parameter type %x", kind));
+ }
+
+ if (!is_valid_ser_string (ctx, &ptr, end))
+ return FALSE;
+
+ if (!is_valid_fixed_param (ctx, type, &ptr, end))
+ return FALSE;
+
+ }
+
return TRUE;
}
static gboolean
is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
{
- int size = 0;
+ guint32 size = 0;
unsigned signature = 0;
const char *ptr = NULL, *end;
--ptr;
if (signature == 0x07)
return parse_locals_signature (ctx, &ptr, end);
+
+ /*F# and managed C++ produce standalonesig for fields even thou the spec doesn't mention it.*/
+ if (signature == 0x06)
+ return parse_field (ctx, &ptr, end);
+
return parse_method_signature (ctx, &ptr, end, TRUE, TRUE);
}
static gboolean
is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
{
- int size = 0;
+ guint32 size = 0;
const char *ptr = NULL, *end;
if (!decode_signature_header (ctx, offset, &size, &ptr))
static gboolean
is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
{
- int size = 0;
+ guint32 size = 0;
const char *ptr = NULL, *end;
- guint8 type = 0;
+ unsigned type = 0;
-
if (!decode_signature_header (ctx, offset, &size, &ptr))
FAIL (ctx, g_strdup ("TypeSpec: Could not decode signature header"));
end = ptr + size;
if (!safe_read8 (type, ptr, end))
FAIL (ctx, g_strdup ("TypeSpec: Not enough room for type"));
- --ptr;
+ if (type == MONO_TYPE_BYREF) {
+ if (!safe_read8 (type, ptr, end))
+ FAIL (ctx, g_strdup ("TypeSpec: Not enough room for byref type"));
+ if (type == MONO_TYPE_TYPEDBYREF)
+ FAIL (ctx, g_strdup ("TypeSpec: Invalid type typedref&"));
+ }
+
if (type == MONO_TYPE_TYPEDBYREF)
return TRUE;
+ --ptr;
return parse_type (ctx, &ptr, end);
}
static gboolean
-is_valid_methodspec_blog (VerifyContext *ctx, guint32 offset)
+is_valid_methodspec_blob (VerifyContext *ctx, guint32 offset)
{
- int size = 0;
+ guint32 size = 0;
const char *ptr = NULL, *end;
- guint8 type = 0;
- guint32 count = 0, i;
+ unsigned type = 0;
+ unsigned count = 0, i;
if (!decode_signature_header (ctx, offset, &size, &ptr))
FAIL (ctx, g_strdup ("MethodSpec: Could not decode signature header"));
}
static gboolean
-is_valid_blob_object (VerifyContext *ctx, guint32 offset)
+is_valid_blob_object (VerifyContext *ctx, guint32 offset, guint32 minsize)
{
OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
guint32 entry_size, bytes;
if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
return FALSE;
- if (offset + entry_size + bytes < offset)
+ if (entry_size < minsize)
+ return FALSE;
+
+ if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
return FALSE;
+ entry_size += bytes;
- return blob.size >= offset + entry_size + bytes;
+ return !ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size);
}
static gboolean
#define SECTION_HEADER_INVALID_FLAGS 0x3E
static gboolean
-is_valid_method_header (VerifyContext *ctx, guint32 rva)
+is_valid_method_header (VerifyContext *ctx, guint32 rva, guint32 *locals_token)
{
- guint32 local_vars_tok, code_size, offset = mono_cli_rva_image_map (ctx->image, rva);
- guint8 header = 0;
- guint16 fat_header = 0, size = 0, max_stack;
+ unsigned local_vars_tok, code_size, offset = mono_cli_rva_image_map (ctx->image, rva);
+ unsigned header = 0;
+ unsigned fat_header = 0, size = 0, max_stack;
const char *ptr = NULL, *end;
+ *locals_token = 0;
+
if (offset == INVALID_ADDRESS)
FAIL (ctx, g_strdup ("MethodHeader: Invalid RVA"));
FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature table 0x%x", ((local_vars_tok >> 24) & 0xFF)));
if ((local_vars_tok & 0xFFFFFF) > ctx->image->tables [MONO_TABLE_STANDALONESIG].rows)
FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature points to invalid row 0x%x", local_vars_tok & 0xFFFFFF));
+ *locals_token = local_vars_tok & 0xFFFFFF;
}
if (fat_header & FAT_HEADER_INVALID_FLAGS)
ptr += code_size;
do {
- guint32 section_header = 0, section_size = 0;
+ unsigned section_header = 0, section_size = 0;
gboolean is_fat;
ptr = dword_align (ptr);
FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section content %d", section_size));
if (section_header & METHOD_HEADER_SECTION_EHTABLE) {
- guint32 i, clauses = (section_size - 4) / (is_fat ? 24 : 12);
- if (clauses * (is_fat ? 24 : 12) + 4 != section_size)
- FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid EH section size %d, it's not of the proper size", section_size));
+ guint32 i, clauses = section_size / (is_fat ? 24 : 12);
+ /*
+ LAMEIMPL: MS emits section_size without accounting for header size.
+ Mono does as the spec says. section_size is header + section
+ MS's peverify happily accepts both.
+ */
+ if ((clauses * (is_fat ? 24 : 12) != section_size) && (clauses * (is_fat ? 24 : 12) + 4 != section_size))
+ 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)));
/* only verify the class token is verified as the rest is done by the IL verifier*/
for (i = 0; i < clauses; ++i) {
- guint32 class_token = 0;
+ unsigned flags = *(unsigned char*)ptr;
+ unsigned class_token = 0;
ptr += (is_fat ? 20 : 8);
if (!safe_read32 (class_token, ptr, end))
FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section %d", i));
- if (!*ptr == MONO_EXCEPTION_CLAUSE_NONE && class_token) {
+ if (flags == MONO_EXCEPTION_CLAUSE_NONE && class_token) {
guint table = mono_metadata_token_table (class_token);
if (table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPESPEC)
FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token table %x", i, table));
{
MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
guint32 data [MONO_TYPEDEF_SIZE];
- guint32 fieldlist = 1, methodlist = 1;
+ guint32 fieldlist = 1, methodlist = 1, visibility;
int i;
if (table->rows == 0)
if (data [MONO_TYPEDEF_EXTENDS] && !is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
+ visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
+ if ((visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) &&
+ search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1) == -1)
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d has nested visibility but no rows in the NestedClass table", i));
+
if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
if (i == 0) {
- if (data [MONO_TYPEDEF_EXTENDS] != 0)
+ /*XXX it's ok if <module> extends object, or anything at all, actually. */
+ /*if (data [MONO_TYPEDEF_EXTENDS] != 0)
ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
+ */
continue;
}
if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
+ if (data [MONO_FIELD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_FIELD_SIGNATURE], 1))
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature blob token 0x%x", i, data [MONO_FIELD_SIGNATURE]));
+
//TODO verify contant flag
if (i + 1 < module_field_list) {
}
}
-/*bits 6,8,9,10,11,13,14,15*/
-#define INVALID_METHOD_IMPLFLAG_BITS ((1 << 6) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
+/*bits 8,9,10,11,13,14,15*/
+#define INVALID_METHOD_IMPLFLAG_BITS ((1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
static void
verify_method_table (VerifyContext *ctx)
{
if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
+ if (flags & METHOD_ATTRIBUTE_FINAL)
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and Final", i));
if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
}
if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
- ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
+ ADD_WARNING (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
//TODO check iface with .ctor (15,16)
- if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
- ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
-
if (i + 1 < module_method_list) {
if (!(flags & METHOD_ATTRIBUTE_STATIC))
ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
- if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && (flags & METHOD_ATTRIBUTE_VIRTUAL))
- ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
+ if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
+ if (flags & METHOD_ATTRIBUTE_VIRTUAL)
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
+ if (!(flags & METHOD_ATTRIBUTE_STATIC))
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but not Static", i));
+ }
if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
!(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
+ if (data [MONO_METHOD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHOD_SIGNATURE], 1))
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature blob token 0x%x", i, data [MONO_METHOD_SIGNATURE]));
+
if (data [MONO_METHOD_PARAMLIST] == 0)
ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
verify_method_table_full (VerifyContext *ctx)
{
MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
- guint32 data [MONO_METHOD_SIZE], rva;
+ guint32 data [MONO_METHOD_SIZE], rva, locals_token;
int i;
for (i = 0; i < table->rows; ++i) {
mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
rva = data [MONO_METHOD_RVA];
-
- if (rva && !is_valid_method_header (ctx, rva))
+
+ if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
+
+ if (rva && !is_valid_method_header (ctx, rva, &locals_token))
ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
}
}
if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
+
+ if (data [MONO_MEMBERREF_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_MEMBERREF_SIGNATURE], 1))
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d invalid signature blob token 0x%x", i, data [MONO_MEMBERREF_SIGNATURE]));
}
}
if (!is_valid_coded_index (ctx, CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]))
ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
+
+ if (data [MONO_CUSTOM_ATTR_VALUE] && !is_valid_blob_object (ctx, data [MONO_CUSTOM_ATTR_VALUE], 0))
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d invalid value blob 0x%x", i, data [MONO_CUSTOM_ATTR_VALUE]));
}
}
verify_cattr_table_full (VerifyContext *ctx)
{
MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
- guint32 data [MONO_CUSTOM_ATTR_SIZE];
+ MonoMethod *ctor;
+ const char *ptr;
+ guint32 data [MONO_CUSTOM_ATTR_SIZE], mtoken, size;
int i;
for (i = 0; i < table->rows; ++i) {
mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
- if (!is_vald_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
+ if (!is_valid_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
+
+ mtoken = data [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
+ switch (data [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
+ case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
+ mtoken |= MONO_TOKEN_METHOD_DEF;
+ break;
+ case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
+ mtoken |= MONO_TOKEN_MEMBER_REF;
+ break;
+ default:
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute constructor row %d Token 0x%08x", i, data [MONO_CUSTOM_ATTR_TYPE]));
+ }
+
+ ctor = mono_get_method (ctx->image, mtoken, NULL);
+
+ /*This can't fail since this is checked in is_valid_cattr_blob*/
+ g_assert (decode_signature_header (ctx, data [MONO_CUSTOM_ATTR_VALUE], &size, &ptr));
+
+ if (!is_valid_cattr_content (ctx, ctor, ptr, size))
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute content row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
}
}
if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
+
+ if (!is_valid_blob_object (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE], 1))
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d invalid NativeType blob 0x%x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
}
}
}
}
+static void
+verify_standalonesig_table (VerifyContext *ctx)
+{
+ MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
+ guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
+ int i;
+
+ for (i = 0; i < table->rows; ++i) {
+ mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
+
+ if (data [MONO_STAND_ALONE_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_STAND_ALONE_SIGNATURE], 1))
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d invalid signature 0x%x", i, data [MONO_STAND_ALONE_SIGNATURE]));
+ }
+}
+
static void
verify_standalonesig_table_full (VerifyContext *ctx)
{
}
static void
-verify_typespec_table_full (VerifyContext *ctx)
+verify_typespec_table (VerifyContext *ctx)
{
MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
guint32 data [MONO_TYPESPEC_SIZE];
for (i = 0; i < table->rows; ++i) {
mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
+ if (data [MONO_TYPESPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_TYPESPEC_SIGNATURE], 1))
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
+ }
+}
+
+static void
+verify_typespec_table_full (VerifyContext *ctx)
+{
+ MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
+ guint32 data [MONO_TYPESPEC_SIZE];
+ int i;
+
+ for (i = 0; i < table->rows; ++i) {
+ mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
+ ctx->token = (i + 1) | MONO_TOKEN_TYPE_SPEC;
if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
}
+ ctx->token = 0;
}
-#define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 6) | (1 << 8) | (1 << 9) | (1 << 10))
+#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))
static void
verify_implmap_table (VerifyContext *ctx)
{
}
}
-#define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 8) | (1 << 14) | (1 << 15))
+#define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 4) | (1 << 8) | (1 << 14) | (1 << 15))
static void
verify_assembly_table (VerifyContext *ctx)
{
if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
- if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY]))
+ if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY], 1))
ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
- if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY]))
+ if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY], 1))
ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
- if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE]))
+ if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE], 1))
ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
}
}
if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
- if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE]))
+ if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE], 1))
ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
}
}
if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
+
+ if (data [MONO_METHODSPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHODSPEC_SIGNATURE], 1))
+ ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid signature token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
}
}
for (i = 0; i < table->rows; ++i) {
mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
- if (!is_valid_methodspec_blog (ctx, data [MONO_METHODSPEC_SIGNATURE]))
+ if (!is_valid_methodspec_blob (ctx, data [MONO_METHODSPEC_SIGNATURE]))
ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
}
}
}
}
+
+typedef struct {
+ const char *name;
+ const char *name_space;
+ guint32 resolution_scope;
+} TypeDefUniqueId;
+
+static guint
+typedef_hash (gconstpointer _key)
+{
+ const TypeDefUniqueId *key = _key;
+ return g_str_hash (key->name) ^ g_str_hash (key->name_space) ^ key->resolution_scope; /*XXX better salt the int key*/
+}
+
+static gboolean
+typedef_equals (gconstpointer _a, gconstpointer _b)
+{
+ const TypeDefUniqueId *a = _a;
+ const TypeDefUniqueId *b = _b;
+ return !strcmp (a->name, b->name) && !strcmp (a->name_space, b->name_space) && a->resolution_scope == b->resolution_scope;
+}
+
+static void
+verify_typedef_table_global_constraints (VerifyContext *ctx)
+{
+ int i;
+ guint32 data [MONO_TYPEDEF_SIZE];
+ guint32 nested_data [MONO_NESTED_CLASS_SIZE];
+ MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
+ MonoTableInfo *nested_table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
+ GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
+
+ for (i = 0; i < table->rows; ++i) {
+ guint visibility;
+ TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
+ mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
+
+ type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAME]);
+ type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAMESPACE]);
+ type->resolution_scope = 0;
+
+ visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
+ if (visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) {
+ int res = search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1);
+ g_assert (res >= 0);
+
+ mono_metadata_decode_row (nested_table, res, nested_data, MONO_NESTED_CLASS_SIZE);
+ type->resolution_scope = nested_data [MONO_NESTED_CLASS_ENCLOSING];
+ }
+
+ if (g_hash_table_lookup (unique_types, type)) {
+ 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));
+ g_hash_table_destroy (unique_types);
+ g_free (type);
+ return;
+ }
+ g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
+ }
+
+ g_hash_table_destroy (unique_types);
+}
+
+static void
+verify_typeref_table_global_constraints (VerifyContext *ctx)
+{
+ int i;
+ guint32 data [MONO_TYPEREF_SIZE];
+ MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
+ GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
+
+ for (i = 0; i < table->rows; ++i) {
+ TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
+ mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
+
+ type->resolution_scope = data [MONO_TYPEREF_SCOPE];
+ type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAME]);
+ type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAMESPACE]);
+
+ if (g_hash_table_lookup (unique_types, type)) {
+ 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));
+ g_hash_table_destroy (unique_types);
+ g_free (type);
+ return;
+ }
+ g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
+ }
+
+ g_hash_table_destroy (unique_types);
+}
+
+static void
+verify_tables_data_global_constraints (VerifyContext *ctx)
+{
+ verify_typedef_table_global_constraints (ctx);
+}
+
+static void
+verify_tables_data_global_constraints_full (VerifyContext *ctx)
+{
+ verify_typeref_table_global_constraints (ctx);
+}
+
static void
verify_tables_data (VerifyContext *ctx)
{
CHECK_ERROR ();
verify_field_layout_table (ctx);
CHECK_ERROR ();
+ verify_standalonesig_table (ctx);
+ CHECK_ERROR ();
verify_eventmap_table (ctx);
CHECK_ERROR ();
verify_event_table (ctx);
CHECK_ERROR ();
verify_moduleref_table (ctx);
CHECK_ERROR ();
+ verify_typespec_table (ctx);
+ CHECK_ERROR ();
verify_implmap_table (ctx);
CHECK_ERROR ();
verify_fieldrva_table (ctx);
verify_method_spec_table (ctx);
CHECK_ERROR ();
verify_generic_param_constraint_table (ctx);
+ CHECK_ERROR ();
+ verify_tables_data_global_constraints (ctx);
}
static void
-init_verify_context (VerifyContext *ctx, MonoImage *image, GSList **error_list)
+init_verify_context (VerifyContext *ctx, MonoImage *image, gboolean report_error)
{
memset (ctx, 0, sizeof (VerifyContext));
ctx->image = image;
- ctx->report_error = error_list != NULL;
+ ctx->report_error = report_error;
+ ctx->report_warning = FALSE; //export this setting in the API
ctx->valid = 1;
ctx->size = image->raw_data_len;
ctx->data = image->raw_data;
return ctx->valid;
}
+static gboolean
+cleanup_context_checked (VerifyContext *ctx, MonoError *error)
+{
+ g_free (ctx->sections);
+ if (ctx->errors) {
+ MonoVerifyInfo *info = ctx->errors->data;
+ mono_error_set_bad_image (error, ctx->image, "%s", info->message);
+ mono_free_verify_list (ctx->errors);
+ }
+ return ctx->valid;
+}
+
gboolean
mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
{
if (!mono_verifier_is_enabled_for_image (image))
return TRUE;
- init_verify_context (&ctx, image, error_list);
+ init_verify_context (&ctx, image, error_list != NULL);
ctx.stage = STAGE_PE;
verify_msdos_header (&ctx);
if (!mono_verifier_is_enabled_for_image (image))
return TRUE;
- init_verify_context (&ctx, image, error_list);
+ init_verify_context (&ctx, image, error_list != NULL);
ctx.stage = STAGE_CLI;
verify_cli_header (&ctx);
if (!mono_verifier_is_enabled_for_image (image))
return TRUE;
- init_verify_context (&ctx, image, error_list);
+ init_verify_context (&ctx, image, error_list != NULL);
ctx.stage = STAGE_TABLES;
verify_tables_data (&ctx);
if (!mono_verifier_is_enabled_for_image (image))
return TRUE;
- init_verify_context (&ctx, image, error_list);
+ init_verify_context (&ctx, image, error_list != NULL);
ctx.stage = STAGE_TABLES;
verify_typedef_table_full (&ctx);
verify_typespec_table_full (&ctx);
CHECK_STATE ();
verify_method_spec_table_full (&ctx);
+ CHECK_STATE ();
+ verify_tables_data_global_constraints_full (&ctx);
cleanup:
return cleanup_context (&ctx, error_list);
if (!mono_verifier_is_enabled_for_image (image))
return TRUE;
- init_verify_context (&ctx, image, error_list);
+ init_verify_context (&ctx, image, error_list != NULL);
ctx.stage = STAGE_TABLES;
is_valid_field_signature (&ctx, offset);
gboolean
mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
+{
+ VerifyContext ctx;
+ guint32 locals_token;
+
+ if (!mono_verifier_is_enabled_for_image (image))
+ return TRUE;
+
+ init_verify_context (&ctx, image, error_list != NULL);
+ ctx.stage = STAGE_TABLES;
+
+ is_valid_method_header (&ctx, offset, &locals_token);
+ if (locals_token) {
+ guint32 sig_offset = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_STANDALONESIG], locals_token - 1, MONO_STAND_ALONE_SIGNATURE);
+ is_valid_standalonesig_blob (&ctx, sig_offset);
+ }
+
+ return cleanup_context (&ctx, error_list);
+}
+
+gboolean
+mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, MonoError *error)
+{
+ VerifyContext ctx;
+
+ mono_error_init (error);
+
+ if (!mono_verifier_is_enabled_for_image (image))
+ return TRUE;
+
+ init_verify_context (&ctx, image, TRUE);
+ ctx.stage = STAGE_TABLES;
+
+ is_valid_method_signature (&ctx, offset);
+ /*XXX This returns a bad image exception, it might be the case that the right exception is method load.*/
+ return cleanup_context_checked (&ctx, error);
+}
+
+gboolean
+mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
+{
+ VerifyContext ctx;
+
+ if (!mono_verifier_is_enabled_for_image (image))
+ return TRUE;
+
+ init_verify_context (&ctx, image, error_list != NULL);
+ ctx.stage = STAGE_TABLES;
+
+ is_valid_method_or_field_signature (&ctx, offset);
+ return cleanup_context (&ctx, error_list);
+}
+
+gboolean
+mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
+{
+ VerifyContext ctx;
+
+ if (!mono_verifier_is_enabled_for_image (image))
+ return TRUE;
+
+ init_verify_context (&ctx, image, error_list != NULL);
+ ctx.stage = STAGE_TABLES;
+
+ is_valid_standalonesig_blob (&ctx, offset);
+ return cleanup_context (&ctx, error_list);
+}
+
+gboolean
+mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
+{
+ VerifyContext ctx;
+
+ if (!mono_verifier_is_enabled_for_image (image))
+ return TRUE;
+
+ init_verify_context (&ctx, image, error_list != NULL);
+ ctx.stage = STAGE_TABLES;
+ ctx.token = token;
+
+ is_valid_typespec_blob (&ctx, offset);
+ return cleanup_context (&ctx, error_list);
+}
+
+gboolean
+mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
+{
+ VerifyContext ctx;
+
+ if (!mono_verifier_is_enabled_for_image (image))
+ return TRUE;
+
+ init_verify_context (&ctx, image, error_list != NULL);
+ ctx.stage = STAGE_TABLES;
+
+ is_valid_methodspec_blob (&ctx, offset);
+ return cleanup_context (&ctx, error_list);
+}
+
+static void
+verify_user_string (VerifyContext *ctx, guint32 offset)
+{
+ OffsetAndSize heap_us = get_metadata_stream (ctx, &ctx->image->heap_us);
+ guint32 entry_size, bytes;
+
+ if (heap_us.size < offset)
+ ADD_ERROR (ctx, g_strdup ("User string offset beyond heap_us size"));
+
+ if (!decode_value (ctx->data + offset + heap_us.offset, heap_us.size - heap_us.offset, &entry_size, &bytes))
+ ADD_ERROR (ctx, g_strdup ("Could not decode user string blob size"));
+
+ if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
+ ADD_ERROR (ctx, g_strdup ("User string size overflow"));
+
+ entry_size += bytes;
+
+ if (ADD_IS_GREATER_OR_OVF (offset, entry_size, heap_us.size))
+ ADD_ERROR (ctx, g_strdup ("User string oveflow heap_us"));
+}
+
+gboolean
+mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
{
VerifyContext ctx;
if (!mono_verifier_is_enabled_for_image (image))
return TRUE;
- init_verify_context (&ctx, image, error_list);
+ init_verify_context (&ctx, image, error_list != NULL);
ctx.stage = STAGE_TABLES;
- is_valid_method_header (&ctx, offset);
+ verify_user_string (&ctx, offset);
+
return cleanup_context (&ctx, error_list);
}
+gboolean
+mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, GSList **error_list)
+{
+ VerifyContext ctx;
+
+ if (!mono_verifier_is_enabled_for_image (image))
+ return TRUE;
+
+ init_verify_context (&ctx, image, error_list != NULL);
+ ctx.stage = STAGE_TABLES;
+
+ is_valid_cattr_blob (&ctx, offset);
+
+ return cleanup_context (&ctx, error_list);
+}
+
+gboolean
+mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, GSList **error_list)
+{
+ VerifyContext ctx;
+
+ if (!mono_verifier_is_enabled_for_image (image))
+ return TRUE;
+
+ init_verify_context (&ctx, image, error_list != NULL);
+ ctx.stage = STAGE_TABLES;
+
+ is_valid_cattr_content (&ctx, ctor, (const char*)data, size);
+
+ return cleanup_context (&ctx, error_list);
+}
+
+gboolean
+mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
+{
+ MonoMethodSignature *original_sig;
+ if (!mono_verifier_is_enabled_for_image (image))
+ return TRUE;
+
+ original_sig = mono_method_signature (method);
+ if (original_sig->call_convention == MONO_CALL_VARARG) {
+ if (original_sig->hasthis != signature->hasthis)
+ return FALSE;
+ if (original_sig->call_convention != signature->call_convention)
+ return FALSE;
+ if (original_sig->explicit_this != signature->explicit_this)
+ return FALSE;
+ if (original_sig->call_convention != signature->call_convention)
+ return FALSE;
+ if (original_sig->pinvoke != signature->pinvoke)
+ return FALSE;
+ if (original_sig->sentinelpos != signature->sentinelpos)
+ return FALSE;
+ } else if (!mono_metadata_signature_equal (signature, original_sig)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
#else
gboolean
mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
return TRUE;
}
-
gboolean
mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
{
return TRUE;
}
+gboolean
+mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, MonoError *error)
+{
+ mono_error_init (error);
+ return TRUE;
+}
+
+gboolean
+mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
+{
+ return TRUE;
+}
+
+gboolean
+mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
+{
+ return TRUE;
+}
+
+gboolean
+mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
+{
+ return TRUE;
+}
+
+gboolean
+mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
+{
+ return TRUE;
+}
+
+gboolean
+mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
+{
+ return TRUE;
+}
+
+gboolean
+mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, GSList **error_list)
+{
+ return TRUE;
+}
+
+gboolean
+mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, GSList **error_list)
+{
+ return TRUE;
+}
+
+gboolean
+mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
+{
+ return TRUE;
+}
+
+
#endif /* DISABLE_VERIFIER */