#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,
guint32 size;
GSList *errors;
int valid;
- gboolean is_corlib;
MonoImage *image;
gboolean report_error;
int stage;
#endif
#define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
+#define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
static const char *
dword_align (const char *ptr)
return strcmp (str, get_string_ptr (ctx, offset));
}
+static gboolean
+mono_verifier_is_corlib (MonoImage *image)
+{
+ gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ?
+ TRUE : mono_security_core_clr_is_platform_image (image);
+
+ return trusted_location && image->module_name && !strcmp ("mscorlib.dll", image->module_name);
+}
+
static gboolean
typedef_is_system_object (VerifyContext *ctx, guint32 *data)
{
- return ctx->is_corlib && !string_cmp (ctx, "System", data [MONO_TYPEDEF_NAME]) && !string_cmp (ctx, "Object", data [MONO_TYPEDEF_NAMESPACE]);
+ return mono_verifier_is_corlib (ctx->image) && !string_cmp (ctx, "System", data [MONO_TYPEDEF_NAMESPACE]) && !string_cmp (ctx, "Object", data [MONO_TYPEDEF_NAME]);
}
static gboolean
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));
}
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_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
guint32 size, entry_size, bytes;
if (blob.size < offset)
- return FALSE;
+ FAIL (ctx, g_strdup ("ContantValue: invalid offset"));
if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
- return FALSE;
+ FAIL (ctx, g_strdup ("ContantValue: not enough space to decode size"));
if (type == MONO_TYPE_STRING) {
- //String is encoded as: compressed_int:len len *chars
-
+ //String is encoded as: compressed_int:len len *bytes
offset += bytes;
- if (offset > offset + entry_size * 2) //overflow
- return FALSE;
- offset += offset + entry_size * 2;
- return offset <= blob.size;
+
+ if (ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size))
+ FAIL (ctx, g_strdup_printf ("ContantValue: not enough space for string, required %d but got %d", entry_size * 2, blob.size - offset));
+
+ return TRUE;
}
switch (type) {
}
if (size != entry_size)
- return FALSE;
- offset += bytes;
+ FAIL (ctx, g_strdup_printf ("ContantValue: Expected size %d but got %d", size, entry_size));
- if(offset > offset + size) //overflow
- return FALSE;
+ offset += bytes;
- if (offset + size > blob.size)
- return FALSE;
+ if (ADD_IS_GREATER_OR_OVF (offset, size, blob.size))
+ FAIL (ctx, g_strdup_printf ("ContantValue: Not enough room for constant, required %d but have %d", size, blob.size - offset));
- if (type == MONO_TYPE_CLASS && read32 (ctx->data + offset))
- return FALSE;
+ if (type == MONO_TYPE_CLASS && read32 (ctx->data + blob.offset + offset))
+ FAIL (ctx, g_strdup_printf ("ContantValue: Type is class but value is not null"));
return TRUE;
}
case 2:
header >>= 2;
if (ADDP_IS_GREATER_OR_OVF (ptr, header, end))
- FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for method body. Required %d, but only %d is available", header, end - ptr));
+ FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for method body. Required %d, but only %d is available", header, (int)(end - ptr)));
return TRUE;
}
//FAT HEADER
/* only verify the class token is verified as the rest is done by the IL verifier*/
for (i = 0; i < clauses; ++i) {
+ guint flags = *ptr;
guint32 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));
if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
+ if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) && (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
+
if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
- if (i == 0) {
- 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"));
- } else {
- if (typedef_is_system_object (ctx, data) && data [MONO_TYPEDEF_EXTENDS] != 0)
- ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
-
- if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
- if (data [MONO_TYPEDEF_EXTENDS])
- ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
- if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
- ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
- } else {
- if (!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]));
-
- if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
- ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
- }
- }
+ 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]));
if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
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));
-
fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
methodlist = data [MONO_TYPEDEF_METHOD_LIST];
}
}
+static void
+verify_typedef_table_full (VerifyContext *ctx)
+{
+ MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
+ guint32 data [MONO_TYPEDEF_SIZE];
+ int i;
+
+ if (table->rows == 0)
+ ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
+
+ for (i = 0; i < table->rows; ++i) {
+ mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
+
+ if (i == 0) {
+ 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_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
+ if (data [MONO_TYPEDEF_EXTENDS])
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
+ } else {
+ gboolean is_sys_obj = typedef_is_system_object (ctx, data);
+ gboolean has_parent = get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]) != 0;
+
+ if (is_sys_obj) {
+ if (has_parent)
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
+ } else {
+ if (!has_parent) {
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
+ }
+ }
+ }
+ }
+}
+
/*bits 3,11,14 */
#define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
static void
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 (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
- ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
if (i + 1 < module_field_list) {
guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
}
}
+static void
+verify_field_table_full (VerifyContext *ctx)
+{
+ MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
+ guint32 data [MONO_FIELD_SIZE];
+ int i;
+
+ for (i = 0; i < table->rows; ++i) {
+ mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
+
+ if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
+ }
+}
+
/*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))
static void
//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));
ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", i));
if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
- if (!is_valid_method_header (ctx, rva))
- ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
} else {
if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
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));
}
}
+static void
+verify_method_table_full (VerifyContext *ctx)
+{
+ MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
+ guint32 data [MONO_METHOD_SIZE], rva;
+ 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 (!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))
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
+ }
+}
+
static guint32
get_next_param_count (VerifyContext *ctx, guint32 *current_method)
{
gboolean first_param = TRUE;
int i;
+ if (ctx->image->tables [MONO_TABLE_METHOD].rows == 0) {
+ if (table->rows > 0)
+ ADD_ERROR (ctx, g_strdup ("Param table has rows while the method table has zero"));
+ return;
+ }
+
remaining_params = get_next_param_count (ctx, ¤t_method);
for (i = 0; i < table->rows; ++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]));
+ }
+}
+
+
+static void
+verify_memberref_table_full (VerifyContext *ctx)
+{
+ MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
+ guint32 data [MONO_MEMBERREF_SIZE];
+ int i;
+
+ for (i = 0; i < table->rows; ++i) {
+ mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
+
if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field 0x%08x", 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]));
+ }
+}
+
+static void
+verify_cattr_table_full (VerifyContext *ctx)
+{
+ MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
+ guint32 data [MONO_CUSTOM_ATTR_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]))
ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute 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_field_marshal_table_full (VerifyContext *ctx)
+{
+ MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
+ guint32 data [MONO_FIELD_MARSHAL_SIZE];
+ int i;
+
+ for (i = 0; i < table->rows; ++i) {
+ mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
+
if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
-
}
}
if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
+ }
+}
+
+static void
+verify_decl_security_table_full (VerifyContext *ctx)
+{
+ MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
+ guint32 data [MONO_DECL_SECURITY_SIZE];
+ int i;
+
+ for (i = 0; i < table->rows; ++i) {
+ mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
-
}
}
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)
+{
+ 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);
verify_event_table (VerifyContext *ctx)
{
MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
- MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
- guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
- gboolean found_add, found_remove;
- int i, idx;
+ guint32 data [MONO_EVENT_SIZE];
+ int i;
for (i = 0; i < table->rows; ++i) {
mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
+ }
+}
+
+static void
+verify_event_table_full (VerifyContext *ctx)
+{
+ MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
+ MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
+ guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
+ gboolean found_add, found_remove;
+ int i, idx;
+
+ for (i = 0; i < table->rows; ++i) {
+ mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
- //check for Add and Remove
token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
if (idx == -1)
guint32 data [MONO_TYPESPEC_SIZE];
int i;
+ 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);
}
}
-#define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10))
+#define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 6) | (1 << 8) | (1 << 9) | (1 << 10))
static void
verify_implmap_table (VerifyContext *ctx)
{
if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
- if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULE].rows + 1)
+ if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULEREF].rows + 1)
ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
}
}
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]));
+ }
+}
+
+static void
+verify_method_spec_table_full (VerifyContext *ctx)
+{
+ MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
+ guint32 data [MONO_METHODSPEC_SIZE];
+ int i;
+
+ 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]))
ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
}
verify_generic_param_constraint_table (ctx);
}
-static gboolean
-mono_verifier_is_corlib (MonoImage *image)
-{
- gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ?
- TRUE : mono_security_core_clr_is_platform_image (image);
-
- return trusted_location && !strcmp ("mscorlib.dll", image->name);
-}
-
static void
init_verify_context (VerifyContext *ctx, MonoImage *image, GSList **error_list)
{
ctx->valid = 1;
ctx->size = image->raw_data_len;
ctx->data = image->raw_data;
- ctx->is_corlib = mono_verifier_is_corlib (image);
}
static gboolean
return cleanup_context (&ctx, error_list);
}
+
+/*
+ * Verifies basic table constraints such as global table invariants (sorting, field monotonicity, etc).
+ * Other verification checks are meant to be done lazily by the runtime. Those include:
+ * blob items (signatures, method headers, custom attributes, etc)
+ * type semantics related
+ * vtable related
+ * stuff that should not block other pieces from running such as bad types/methods/fields/etc.
+ *
+ * The whole idea is that if this succeed the runtime is free to play around safely but any complex
+ * operation still need more checking.
+ */
gboolean
mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
{
return cleanup_context (&ctx, error_list);
}
+
+
+/*
+ * Verifies all other constraints.
+ */
+gboolean
+mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
+{
+ VerifyContext ctx;
+
+ if (!mono_verifier_is_enabled_for_image (image))
+ return TRUE;
+
+ init_verify_context (&ctx, image, error_list);
+ ctx.stage = STAGE_TABLES;
+
+ verify_typedef_table_full (&ctx);
+ CHECK_STATE ();
+ verify_field_table_full (&ctx);
+ CHECK_STATE ();
+ verify_method_table_full (&ctx);
+ CHECK_STATE ();
+ verify_memberref_table_full (&ctx);
+ CHECK_STATE ();
+ verify_cattr_table_full (&ctx);
+ CHECK_STATE ();
+ verify_field_marshal_table_full (&ctx);
+ CHECK_STATE ();
+ verify_decl_security_table_full (&ctx);
+ CHECK_STATE ();
+ verify_standalonesig_table_full (&ctx);
+ CHECK_STATE ();
+ verify_event_table_full (&ctx);
+ CHECK_STATE ();
+ verify_typespec_table_full (&ctx);
+ CHECK_STATE ();
+ verify_method_spec_table_full (&ctx);
+
+cleanup:
+ return cleanup_context (&ctx, error_list);
+}
+
+gboolean
+mono_verifier_verify_field_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);
+ ctx.stage = STAGE_TABLES;
+
+ is_valid_field_signature (&ctx, offset);
+ return cleanup_context (&ctx, error_list);
+}
+
+gboolean
+mono_verifier_verify_method_header (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);
+ ctx.stage = STAGE_TABLES;
+
+ is_valid_method_header (&ctx, offset);
+ return cleanup_context (&ctx, error_list);
+}
+
+gboolean
+mono_verifier_verify_method_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);
+ ctx.stage = STAGE_TABLES;
+
+ is_valid_method_signature (&ctx, offset);
+ return cleanup_context (&ctx, error_list);
+}
+
+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);
+ 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);
+ 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, GSList **error_list)
+{
+ VerifyContext ctx;
+
+ if (!mono_verifier_is_enabled_for_image (image))
+ return TRUE;
+
+ init_verify_context (&ctx, image, error_list);
+ ctx.stage = STAGE_TABLES;
+
+ 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);
+ ctx.stage = STAGE_TABLES;
+
+ is_valid_methodspec_blog (&ctx, offset);
+ return cleanup_context (&ctx, error_list);
+}
+
#else
gboolean
mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
{
return TRUE;
}
+
+gboolean
+mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
+{
+ return TRUE;
+}
+
+gboolean
+mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, 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, GSList **error_list)
+{
+ 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, GSList **error_list)
+{
+ return TRUE;
+}
+
+gboolean
+mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
+{
+ return TRUE;
+}
+
#endif /* DISABLE_VERIFIER */