Merge pull request #4453 from lambdageek/bug-49721
authorAleksey Kliger (λgeek) <akliger@gmail.com>
Thu, 16 Mar 2017 23:09:00 +0000 (19:09 -0400)
committerGitHub <noreply@github.com>
Thu, 16 Mar 2017 23:09:00 +0000 (19:09 -0400)
[loader] Check strong name when loading from application base. (Fixes #49721)

1  2 
configure.ac
mono/metadata/appdomain.c
mono/metadata/assembly.c

diff --combined configure.ac
index cf871f8e485e0e2e6417a29b6d7d0085a09fba21,4533d289ef958597fadc5c37e13749773d4294ae..433ff566fd7d69a1ce7475421f6914d99e4aae4a
@@@ -29,24 -29,6 +29,24 @@@ AC_PROG_LN_
  
  m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
  
 +MONO_VERSION_MAJOR=`echo $VERSION | cut -d . -f 1`
 +MONO_VERSION_MINOR=`echo $VERSION | cut -d . -f 2`
 +MONO_VERSION_BUILD=`echo $VERSION | cut -d . -f 3`
 +
 +# This is the version number of the corlib-runtime interface. When
 +# making changes to this interface (by changing the layout
 +# of classes the runtime knows about, changing icall signature or
 +# semantics etc), increment this variable.
 +#
 +# This can be reset to 0 when Mono's version number is bumped
 +# since it's part of the corlib version (the prefix '1' in the full
 +# version number is to ensure the number isn't treated as octal in C)
 +MONO_CORLIB_COUNTER=0
 +MONO_CORLIB_VERSION=`printf "1%02d%02d%02d%03d" $MONO_VERSION_MAJOR $MONO_VERSION_MINOR $MONO_VERSION_BUILD $MONO_CORLIB_COUNTER`
 +
 +AC_DEFINE_UNQUOTED(MONO_CORLIB_VERSION,$MONO_CORLIB_VERSION,[Version of the corlib-runtime interface])
 +AC_SUBST(MONO_CORLIB_VERSION)
 +
  case $host_os in
  *cygwin* )
                 echo "Run configure using ./configure --host=i686-pc-mingw32"
@@@ -4443,6 -4425,7 +4443,7 @@@ mono/tests/Makefil
  mono/tests/tests-config
  mono/tests/assemblyresolve/Makefile
  mono/tests/gc-descriptors/Makefile
+ mono/tests/testing_gac/Makefile
  mono/unit-tests/Makefile
  mono/benchmark/Makefile
  mono/mini/Makefile
      }')]
  
      echo "MONO_VERSION = $myver" >> $mcs_topdir/build/config.make
 +    echo "MONO_CORLIB_VERSION = $MONO_CORLIB_VERSION" >> $mcs_topdir/build/config.make
  
      if test x$host_darwin = xyes; then
        echo "PLATFORM = darwin" >> $mcs_topdir/build/config.make
index 77f2c7d123397b532506d8c7fe91cfd03e048579,cbfa2c3c24613e59517c70334e04187846770913..81a92adc2e1a3ceb6b36797384d078e8770b7666
@@@ -38,7 -38,6 +38,6 @@@
  #include <mono/metadata/appdomain-icalls.h>
  #include <mono/metadata/domain-internals.h>
  #include "mono/metadata/metadata-internals.h"
- #include <mono/metadata/assembly.h>
  #include <mono/metadata/assembly-internals.h>
  #include <mono/metadata/exception.h>
  #include <mono/metadata/exception-internals.h>
  #include <direct.h>
  #endif
  
 -/*
 - * This is the version number of the corlib-runtime interface. When
 - * making changes to this interface (by changing the layout
 - * of classes the runtime knows about, changing icall signature or
 - * semantics etc), increment this variable. Also increment the
 - * pair of this variable in mscorlib in:
 - *       mcs/class/corlib/System/Environment.cs
 - *
 - * Changes which are already detected at runtime, like the addition
 - * of icalls, do not require an increment.
 - */
 -#define MONO_CORLIB_VERSION 164
 -
  typedef struct
  {
        int runtime_count;
@@@ -1176,13 -1188,12 +1175,13 @@@ add_assemblies_to_domain (MonoDomain *d
        if (!ht) {
                ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
                destroy_ht = TRUE;
 +              for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
 +                      g_hash_table_insert (ht, tmp->data, tmp->data);
 +              }
        }
  
        /* FIXME: handle lazy loaded assemblies */
 -      for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
 -              g_hash_table_insert (ht, tmp->data, tmp->data);
 -      }
 +
        if (!g_hash_table_lookup (ht, ass)) {
                mono_assembly_addref (ass);
                g_hash_table_insert (ht, ass, ass);
        }
  
        if (ass->image->references) {
 -              for (i = 0; ass->image->references [i] != NULL; i++) {
 -                      if (ass->image->references [i] != REFERENCE_MISSING)
 +              for (i = 0; i < ass->image->nreferences; i++) {
 +                      if (ass->image->references[i] && ass->image->references [i] != REFERENCE_MISSING) {
                                if (!g_hash_table_lookup (ht, ass->image->references [i])) {
                                        add_assemblies_to_domain (domain, ass->image->references [i], ht);
                                }
 +                      }
                }
        }
        if (destroy_ht)
@@@ -1889,9 -1899,11 +1888,11 @@@ leave
  
  
  static gboolean
- try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
-                                       const gchar *path3, const gchar *path4,
-                                       gboolean refonly, gboolean is_private)
+ try_load_from (MonoAssembly **assembly,
+              const gchar *path1, const gchar *path2,
+              const gchar *path3, const gchar *path4,
+              gboolean refonly, gboolean is_private,
+              MonoAssemblyCandidatePredicate predicate, gpointer user_data)
  {
        gchar *fullpath;
        gboolean found = FALSE;
                found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
        
        if (found)
-               *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
+               *assembly = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, user_data, NULL);
  
        g_free (fullpath);
        return (*assembly != NULL);
  }
  
  static MonoAssembly *
- real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
+ real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly, MonoAssemblyCandidatePredicate predicate, gpointer user_data)
  {
        MonoAssembly *result = NULL;
        gchar **path;
                /* See test cases in bug #58992 and bug #57710 */
                /* 1st try: [culture]/[name].dll (culture may be empty) */
                strcpy (filename + len - 4, ".dll");
-               if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
+               if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private, predicate, user_data))
                        break;
  
                /* 2nd try: [culture]/[name].exe (culture may be empty) */
                strcpy (filename + len - 4, ".exe");
-               if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
+               if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private, predicate, user_data))
                        break;
  
                /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
                strcpy (filename + len - 4, ".dll");
-               if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
+               if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private, predicate, user_data))
                        break;
  
                /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
                strcpy (filename + len - 4, ".exe");
-               if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
+               if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private, predicate, user_data))
                        break;
        }
  
@@@ -1985,11 -1997,19 +1986,19 @@@ mono_domain_assembly_preload (MonoAssem
        set_domain_search_path (domain);
  
        if (domain->search_path && domain->search_path [0] != NULL) {
-               result = real_load (domain->search_path, aname->culture, aname->name, refonly);
+               if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY)) {
+                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Domain %s search path is:", domain->friendly_name);
+                       for (int i = 0; domain->search_path [i]; i++) {
+                               const char *p = domain->search_path[i];
+                               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "\tpath[%d] = '%s'", i, p);
+                       }
+                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "End of domain %s search path.", domain->friendly_name);                    
+               }
+               result = real_load (domain->search_path, aname->culture, aname->name, refonly, &mono_assembly_candidate_predicate_sn_same_name, aname);
        }
  
        if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
-               result = real_load (assemblies_path, aname->culture, aname->name, refonly);
+               result = real_load (assemblies_path, aname->culture, aname->name, refonly, &mono_assembly_candidate_predicate_sn_same_name, aname);
        }
  
        return result;
@@@ -2043,7 -2063,7 +2052,7 @@@ ves_icall_System_Reflection_Assembly_Lo
        if (!is_ok (error))
                goto leave;
        
-       MonoAssembly *ass = mono_assembly_open_a_lot (filename, &status, refOnly, TRUE);
+       MonoAssembly *ass = mono_assembly_open_predicate (filename, refOnly, TRUE, NULL, NULL, &status);
        
        if (!ass) {
                if (status == MONO_IMAGE_IMAGE_INVALID)
diff --combined mono/metadata/assembly.c
index fa765bbe5f1d58fb93ac473f664583296442ab6b,94d041ed0d590e9b7f1dafea9a5ceca322e7580b..aa900409470e52ba1c0b1d51e3ed2ca1608d7215
@@@ -528,7 -528,7 +528,7 @@@ mono_assembly_names_equal (MonoAssembly
  }
  
  static MonoAssembly *
- load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly)
+ load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly, MonoAssemblyCandidatePredicate predicate, gpointer user_data)
  {
        int i;
        char *fullpath;
  
        for (i = 0; search_path [i]; ++i) {
                fullpath = g_build_filename (search_path [i], basename, NULL);
-               result = mono_assembly_open_full (fullpath, status, refonly);
+               result = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, user_data, status);
                g_free (fullpath);
                if (result)
                        return result;
@@@ -1125,6 -1125,16 +1125,16 @@@ mono_assembly_remap_version (MonoAssemb
                dest_aname->minor = vset->minor;
                dest_aname->build = vset->build;
                dest_aname->revision = vset->revision;
+               if (current_runtime->public_key_token != NULL &&
+                   dest_aname->public_key_token [0] != 0 &&
+                   !mono_public_tokens_are_equal (dest_aname->public_key_token, (const mono_byte *)current_runtime->public_key_token)) {
+                       mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
+                                   "The request for assembly name '%s' with PublicKeyToken=%s was remapped to PublicKeyToken=%s",
+                                   dest_aname->name,
+                                   dest_aname->public_key_token,
+                                   current_runtime->public_key_token);
+                       memcpy (dest_aname->public_key_token, current_runtime->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
+               }
                if (vmap->new_assembly_name != NULL) {
                        dest_aname->name = vmap->new_assembly_name;
                        mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
@@@ -1677,7 -1687,16 +1687,16 @@@ mono_assembly_open_full (const char *fi
  MonoAssembly *
  mono_assembly_open_a_lot (const char *filename, MonoImageOpenStatus *status, gboolean refonly, gboolean load_from_context)
  {
+       return mono_assembly_open_predicate (filename, refonly, load_from_context, NULL, NULL, status);
+ }
  
+ MonoAssembly *
+ mono_assembly_open_predicate (const char *filename, gboolean refonly,
+                             gboolean load_from_context,
+                             MonoAssemblyCandidatePredicate predicate,
+                             gpointer user_data,
+                             MonoImageOpenStatus *status)
+ {
        MonoImage *image;
        MonoAssembly *ass;
        MonoImageOpenStatus def_status;
                return image->assembly;
        }
  
-       ass = mono_assembly_load_from_full (image, fname, status, refonly);
+       ass = mono_assembly_load_from_predicate (image, fname, refonly, predicate, user_data, status);
  
        if (ass) {
                if (!loaded_from_bundle)
@@@ -1948,7 -1967,7 +1967,7 @@@ mono_assembly_has_reference_assembly_at
  MonoAssembly *
  mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
  {
-       return mono_assembly_open_full (filename, status, FALSE);
+       return mono_assembly_open_predicate (filename, FALSE, FALSE, NULL, NULL, status);
  }
  
  /**
  MonoAssembly *
  mono_assembly_load_from_full (MonoImage *image, const char*fname, 
                              MonoImageOpenStatus *status, gboolean refonly)
+ {
+       return mono_assembly_load_from_predicate (image, fname, refonly, NULL, NULL, status);
+ }
+ MonoAssembly *
+ mono_assembly_load_from_predicate (MonoImage *image, const char *fname,
+                                  gboolean refonly,
+                                  MonoAssemblyCandidatePredicate predicate,
+                                  gpointer user_data,
+                                  MonoImageOpenStatus *status)
  {
        MonoAssembly *ass, *ass2;
        char *base_dir;
                mono_error_cleanup (&refasm_error);
        }
  
+       if (predicate && !predicate (ass, user_data)) {
+               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate returned FALSE, skipping '%s' (%s)\n", ass->aname.name, image->name);
+               g_free (ass);
+               g_free (base_dir);
+               mono_image_close (image);
+               *status = MONO_IMAGE_IMAGE_INVALID;
+               return NULL;
+       }
        mono_assemblies_lock ();
  
        if (image->assembly) {
@@@ -2673,7 -2711,7 +2711,7 @@@ probe_for_partial_name (const char *bas
        if (fullpath == NULL)
                return NULL;
        else {
-               MonoAssembly *res = mono_assembly_open (fullpath, status);
+               MonoAssembly *res = mono_assembly_open_predicate (fullpath, FALSE, FALSE, NULL, NULL, status);
                g_free (fullpath);
                return res;
        }
@@@ -2966,12 -3004,6 +3004,12 @@@ assembly_binding_info_parsed (MonoAssem
        if (!domain)
                return;
  
 +      if (info->has_new_version && mono_assembly_is_problematic_version (info->name, info->new_version.major, info->new_version.minor, info->new_version.build, info->new_version.revision)) {
 +              mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Discarding assembly binding to problematic version %s v%d.%d.%d.%d",
 +                      info->name, info->new_version.major, info->new_version.minor, info->new_version.build, info->new_version.revision);
 +              return;
 +      }
 +
        for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
                info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
                if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
@@@ -3196,7 -3228,7 +3234,7 @@@ mono_assembly_load_from_gac (MonoAssemb
                paths = extra_gac_paths;
                while (!result && *paths) {
                        fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
-                       result = mono_assembly_open_full (fullpath, status, refonly);
+                       result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
                        g_free (fullpath);
                        paths++;
                }
  
        fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
                        "mono", "gac", subpath, NULL);
-       result = mono_assembly_open_full (fullpath, status, refonly);
+       result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
        g_free (fullpath);
  
        if (result)
@@@ -3259,7 -3291,7 +3297,7 @@@ mono_assembly_load_corlib (const MonoRu
  
        // This unusual directory layout can occur if mono is being built and run out of its own source repo
        if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
-               corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
+               corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE, NULL, NULL);
                if (corlib)
                        goto return_corlib_and_facades;
        }
        /* Normal case: Load corlib from mono/<version> */
        corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
        if (assemblies_path) { // Custom assemblies path
-               corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
+               corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE, NULL, NULL);
                if (corlib) {
                        g_free (corlib_file);
                        goto return_corlib_and_facades;
                }
        }
-       corlib = load_in_path (corlib_file, default_path, status, FALSE);
+       corlib = load_in_path (corlib_file, default_path, status, FALSE, NULL, NULL);
        g_free (corlib_file);
  
  return_corlib_and_facades:
@@@ -3295,6 -3327,44 +3333,44 @@@ prevent_reference_assembly_from_runnin
        return candidate;
  }
  
+ gboolean
+ mono_assembly_candidate_predicate_sn_same_name (MonoAssembly *candidate, gpointer ud)
+ {
+       MonoAssemblyName *wanted_name = (MonoAssemblyName*)ud;
+       MonoAssemblyName *candidate_name = &candidate->aname;
+       g_assert (wanted_name != NULL);
+       g_assert (candidate_name != NULL);
+       if (mono_trace_is_traced (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY)) {
+               char * s = mono_stringify_assembly_name (wanted_name);
+               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: wanted = %s\n", s);
+               g_free (s);
+               s = mono_stringify_assembly_name (candidate_name);
+               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate = %s\n", s);
+               g_free (s);
+       }
+       /* No wanted token, bail. */
+       if (0 == wanted_name->public_key_token [0]) {
+               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: wanted has no token, returning TRUE\n");
+               return TRUE;
+       }
+       if (0 == candidate_name->public_key_token [0]) {
+               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate has no token, returning FALSE\n");
+               return FALSE;
+       }
+       gboolean result = mono_assembly_names_equal (wanted_name, candidate_name);
+       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate and wanted names %s\n",
+                   result ? "match, returning TRUE" : "don't match, returning FALSE");
+       return result;
+ }
  
  MonoAssembly*
  mono_assembly_load_full_nosearch (MonoAssemblyName *aname, 
        int len;
  
        aname = mono_assembly_remap_version (aname, &maped_aname);
 -      
 +
        /* Reflection only assemblies don't get assembly binding */
        if (!refonly)
                aname = mono_assembly_apply_binding (aname, &maped_name_pp);
  
                if (basedir) {
                        fullpath = g_build_filename (basedir, filename, NULL);
-                       result = mono_assembly_open_full (fullpath, status, refonly);
+                       result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
                        g_free (fullpath);
                        if (result) {
                                result->in_gac = FALSE;
                        }
                }
  
-               result = load_in_path (filename, default_path, status, refonly);
+               result = load_in_path (filename, default_path, status, refonly, NULL, NULL);
                if (result)
                        result->in_gac = FALSE;
                g_free (filename);