1 /**
2  * \file
3  * Routines for loading assemblies.
4  *
5  * Author:
6  *   Miguel de Icaza (miguel@ximian.com)
7  *
8  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
10  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
11  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
12  */
13 #include <config.h>
14 #include <stdio.h>
15 #include <glib.h>
16 #include <errno.h>
17 #include <string.h>
18 #include <stdlib.h>
19 #include "assembly.h"
20 #include "assembly-internals.h"
21 #include "image.h"
22 #include "image-internals.h"
23 #include "object-internals.h"
24 #include <mono/metadata/loader.h>
25 #include <mono/metadata/tabledefs.h>
26 #include <mono/metadata/custom-attrs-internals.h>
27 #include <mono/metadata/metadata-internals.h>
28 #include <mono/metadata/profiler-private.h>
29 #include <mono/metadata/class-internals.h>
30 #include <mono/metadata/domain-internals.h>
31 #include <mono/metadata/reflection-internals.h>
32 #include <mono/metadata/mono-endian.h>
33 #include <mono/metadata/mono-debug.h>
34 #include <mono/utils/mono-uri.h>
35 #include <mono/metadata/mono-config.h>
36 #include <mono/metadata/mono-config-dirs.h>
37 #include <mono/utils/mono-digest.h>
38 #include <mono/utils/mono-logger-internals.h>
39 #include <mono/utils/mono-path.h>
40 #include <mono/metadata/reflection.h>
41 #include <mono/metadata/coree.h>
42 #include <mono/metadata/cil-coff.h>
43 #include <mono/utils/mono-io-portability.h>
44 #include <mono/utils/atomic.h>
45 #include <mono/utils/mono-os-mutex.h>
46 
47 #ifndef HOST_WIN32
48 #include <sys/types.h>
49 #include <unistd.h>
50 #include <sys/stat.h>
51 #endif
52 
53 #ifdef HOST_DARWIN
54 #include <mach-o/dyld.h>
55 #endif
56 
57 /* AssemblyVersionMap: an assembly name, the assembly version set on which it is based, the assembly name it is replaced with and whether only versions lower than the current runtime version should be remapped */
58 typedef struct  {
59 	const char* assembly_name;
60 	guint8 version_set_index;
61 	const char* new_assembly_name;
62 	gboolean only_lower_versions;
63 	gboolean framework_facade_assembly;
64 } AssemblyVersionMap;
65 
66 /* Flag bits for assembly_names_equal_flags (). */
67 typedef enum {
68 	/* Default comparison: all fields must match */
69 	ANAME_EQ_NONE = 0x0,
70 	/* Don't compare public key token */
71 	ANAME_EQ_IGNORE_PUBKEY = 0x1,
72 	/* Don't compare the versions */
73 	ANAME_EQ_IGNORE_VERSION = 0x2,
74 
75 	ANAME_EQ_MASK = 0x3
76 } AssemblyNameEqFlags;
77 
78 /* the default search path is empty, the first slot is replaced with the computed value */
79 static const char*
80 default_path [] = {
81 	NULL,
82 	NULL,
83 	NULL
84 };
85 
86 /* Contains the list of directories to be searched for assemblies (MONO_PATH) */
87 static char **assemblies_path = NULL;
88 
89 /* Contains the list of directories that point to auxiliary GACs */
90 static char **extra_gac_paths = NULL;
91 
92 #ifndef DISABLE_DESKTOP_LOADER
93 
94 #define FACADE_ASSEMBLY(str) {str, 0, NULL, FALSE, TRUE}
95 
96 static GHashTable* assembly_remapping_table;
97 /* The list of system assemblies what will be remapped to the running
98  * runtime version.
99  * This list is stored in @assembly_remapping_table during initialization.
100  * Keep it sorted just to make maintenance easier.
101  *
102  * The integer number is an index in the MonoRuntimeInfo structure, whose
103  * values can be found in domain.c - supported_runtimes. Look there
104  * to understand what remapping will be made.
105  *
106  * .NET version can be found at https://github.com/dotnet/coreclr/blob/master/src/inc/fxretarget.h#L99
107  *
108  */
109 static const AssemblyVersionMap framework_assemblies [] = {
110 	{"Accessibility", 0},
111 	{"Commons.Xml.Relaxng", 0},
112 	{"I18N", 0},
113 	{"I18N.CJK", 0},
114 	{"I18N.MidEast", 0},
115 	{"I18N.Other", 0},
116 	{"I18N.Rare", 0},
117 	{"I18N.West", 0},
118 	{"Microsoft.Build.Engine", 2, NULL, TRUE},
119 	{"Microsoft.Build.Framework", 2, NULL, TRUE},
120 	{"Microsoft.Build.Tasks", 2, "Microsoft.Build.Tasks.v4.0"},
121 	{"Microsoft.Build.Tasks.v3.5", 2, "Microsoft.Build.Tasks.v4.0"},
122 	{"Microsoft.Build.Utilities", 2, "Microsoft.Build.Utilities.v4.0"},
123 	{"Microsoft.Build.Utilities.v3.5", 2, "Microsoft.Build.Utilities.v4.0"},
124 	{"Microsoft.VisualBasic", 1},
125 	{"Microsoft.VisualC", 1},
126 	FACADE_ASSEMBLY ("Microsoft.Win32.Primitives"),
127 	FACADE_ASSEMBLY ("Microsoft.Win32.Registry"),
128 	FACADE_ASSEMBLY ("Microsoft.Win32.Registry.AccessControl"),
129 	{"Mono.Cairo", 0},
130 	{"Mono.CompilerServices.SymbolWriter", 0},
131 	{"Mono.Data", 0},
132 	{"Mono.Data.SybaseClient", 0},
133 	{"Mono.Data.Tds", 0},
134 	{"Mono.Data.TdsClient", 0},
135 	{"Mono.GetOptions", 0},
136 	{"Mono.Http", 0},
137 	{"Mono.Posix", 0},
138 	{"Mono.Security", 0},
139 	{"Mono.Security.Win32", 0},
140 	{"Mono.Xml.Ext", 0},
141 	{"Novell.Directory.Ldap", 0},
142 	{"PEAPI", 0},
143 	{"System", 0},
144 	FACADE_ASSEMBLY ("System.AppContext"),
145 	FACADE_ASSEMBLY ("System.Collections"),
146 	FACADE_ASSEMBLY ("System.Collections.Concurrent"),
147 	FACADE_ASSEMBLY ("System.Collections.NonGeneric"),
148 	FACADE_ASSEMBLY ("System.Collections.Specialized"),
149 	FACADE_ASSEMBLY ("System.ComponentModel"),
150 	FACADE_ASSEMBLY ("System.ComponentModel.Annotations"),
151 	{"System.ComponentModel.Composition", 2},
152 	{"System.ComponentModel.DataAnnotations", 2},
153 	FACADE_ASSEMBLY ("System.ComponentModel.EventBasedAsync"),
154 	FACADE_ASSEMBLY ("System.ComponentModel.Primitives"),
155 	FACADE_ASSEMBLY ("System.ComponentModel.TypeConverter"),
156 	{"System.Configuration", 0},
157 	{"System.Configuration.Install", 0},
158 	FACADE_ASSEMBLY ("System.Console"),
159 	{"System.Core", 2},
160 	{"System.Data", 0},
161 	FACADE_ASSEMBLY ("System.Data.Common"),
162 	{"System.Data.Linq", 2},
163 	{"System.Data.OracleClient", 0},
164 	{"System.Data.Services", 2},
165 	{"System.Data.Services.Client", 2},
166 	FACADE_ASSEMBLY ("System.Data.SqlClient"),
167 	{"System.Data.SqlXml", 0},
168 	{"System.Design", 0},
169 	FACADE_ASSEMBLY ("System.Diagnostics.Contracts"),
170 	FACADE_ASSEMBLY ("System.Diagnostics.Debug"),
171 	FACADE_ASSEMBLY ("System.Diagnostics.FileVersionInfo"),
172 	FACADE_ASSEMBLY ("System.Diagnostics.Process"),
173 	FACADE_ASSEMBLY ("System.Diagnostics.StackTrace"),
174 	FACADE_ASSEMBLY ("System.Diagnostics.TextWriterTraceListener"),
175 	FACADE_ASSEMBLY ("System.Diagnostics.Tools"),
176 	FACADE_ASSEMBLY ("System.Diagnostics.TraceEvent"),
177 	FACADE_ASSEMBLY ("System.Diagnostics.TraceSource"),
178 	FACADE_ASSEMBLY ("System.Diagnostics.Tracing"),
179 	{"System.DirectoryServices", 0},
180 	{"System.Drawing", 0},
181 	{"System.Drawing.Design", 0},
182 	FACADE_ASSEMBLY ("System.Drawing.Primitives"),
183 	FACADE_ASSEMBLY ("System.Dynamic.Runtime"),
184 	{"System.EnterpriseServices", 0},
185 	FACADE_ASSEMBLY ("System.Globalization"),
186 	FACADE_ASSEMBLY ("System.Globalization.Calendars"),
187 	FACADE_ASSEMBLY ("System.Globalization.Extensions"),
188 	{"System.IdentityModel", 3},
189 	{"System.IdentityModel.Selectors", 3},
190 	FACADE_ASSEMBLY ("System.IO"),
191 	{"System.IO.Compression", 2},
192 	FACADE_ASSEMBLY ("System.IO.Compression.ZipFile"),
193 	FACADE_ASSEMBLY ("System.IO.FileSystem"),
194 	FACADE_ASSEMBLY ("System.IO.FileSystem.AccessControl"),
195 	FACADE_ASSEMBLY ("System.IO.FileSystem.DriveInfo"),
196 	FACADE_ASSEMBLY ("System.IO.FileSystem.Primitives"),
197 	FACADE_ASSEMBLY ("System.IO.FileSystem.Watcher"),
198 	FACADE_ASSEMBLY ("System.IO.IsolatedStorage"),
199 	FACADE_ASSEMBLY ("System.IO.MemoryMappedFiles"),
200 	FACADE_ASSEMBLY ("System.IO.Packaging"),
201 	FACADE_ASSEMBLY ("System.IO.Pipes"),
202 	FACADE_ASSEMBLY ("System.IO.UnmanagedMemoryStream"),
203 	FACADE_ASSEMBLY ("System.Linq"),
204 	FACADE_ASSEMBLY ("System.Linq.Expressions"),
205 	FACADE_ASSEMBLY ("System.Linq.Parallel"),
206 	FACADE_ASSEMBLY ("System.Linq.Queryable"),
207 	{"System.Management", 0},
208 	{"System.Messaging", 0},
209 	{"System.Net", 2},
210 	FACADE_ASSEMBLY ("System.Net.AuthenticationManager"),
211 	FACADE_ASSEMBLY ("System.Net.Cache"),
212 	{"System.Net.Http", 4},
213 	{"System.Net.Http.Rtc", 0},
214 	FACADE_ASSEMBLY ("System.Net.HttpListener"),
215 	FACADE_ASSEMBLY ("System.Net.Mail"),
216 	FACADE_ASSEMBLY ("System.Net.NameResolution"),
217 	FACADE_ASSEMBLY ("System.Net.NetworkInformation"),
218 	FACADE_ASSEMBLY ("System.Net.Ping"),
219 	FACADE_ASSEMBLY ("System.Net.Primitives"),
220 	FACADE_ASSEMBLY ("System.Net.Requests"),
221 	FACADE_ASSEMBLY ("System.Net.Security"),
222 	FACADE_ASSEMBLY ("System.Net.ServicePoint"),
223 	FACADE_ASSEMBLY ("System.Net.Sockets"),
224 	FACADE_ASSEMBLY ("System.Net.Utilities"),
225 	FACADE_ASSEMBLY ("System.Net.WebHeaderCollection"),
226 	FACADE_ASSEMBLY ("System.Net.WebSockets"),
227 	FACADE_ASSEMBLY ("System.Net.WebSockets.Client"),
228 	{"System.Numerics", 3},
229 	{"System.Numerics.Vectors", 3},
230 	FACADE_ASSEMBLY ("System.ObjectModel"),
231 	FACADE_ASSEMBLY ("System.Reflection"),
232 	FACADE_ASSEMBLY ("System.Reflection.DispatchProxy"),
233 	FACADE_ASSEMBLY ("System.Reflection.Emit"),
234 	FACADE_ASSEMBLY ("System.Reflection.Emit.ILGeneration"),
235 	FACADE_ASSEMBLY ("System.Reflection.Emit.Lightweight"),
236 	FACADE_ASSEMBLY ("System.Reflection.Extensions"),
237 	FACADE_ASSEMBLY ("System.Reflection.Primitives"),
238 	FACADE_ASSEMBLY ("System.Reflection.TypeExtensions"),
239 	FACADE_ASSEMBLY ("System.Resources.ReaderWriter"),
240 	FACADE_ASSEMBLY ("System.Resources.ResourceManager"),
241 	FACADE_ASSEMBLY ("System.Runtime"),
242 	FACADE_ASSEMBLY ("System.Runtime.CompilerServices.VisualC"),
243 	FACADE_ASSEMBLY ("System.Runtime.Extensions"),
244 	FACADE_ASSEMBLY ("System.Runtime.Handles"),
245 	FACADE_ASSEMBLY ("System.Runtime.InteropServices"),
246 	FACADE_ASSEMBLY ("System.Runtime.InteropServices.RuntimeInformation"),
247 	FACADE_ASSEMBLY ("System.Runtime.InteropServices.WindowsRuntime"),
248 	FACADE_ASSEMBLY ("System.Runtime.Loader"),
249 	FACADE_ASSEMBLY ("System.Runtime.Numerics"),
250 	{"System.Runtime.Remoting", 0},
251 	{"System.Runtime.Serialization", 3},
252 	FACADE_ASSEMBLY ("System.Runtime.Serialization.Formatters"),
253 	{"System.Runtime.Serialization.Formatters.Soap", 0},
254 	FACADE_ASSEMBLY ("System.Runtime.Serialization.Json"),
255 	FACADE_ASSEMBLY ("System.Runtime.Serialization.Primitives"),
256 	FACADE_ASSEMBLY ("System.Runtime.Serialization.Xml"),
257 	{"System.Security", 0},
258 	FACADE_ASSEMBLY ("System.Security.AccessControl"),
259 	FACADE_ASSEMBLY ("System.Security.Claims"),
260 	FACADE_ASSEMBLY ("System.Security.Cryptography.Algorithms"),
261 	FACADE_ASSEMBLY ("System.Security.Cryptography.Cng"),
262 	FACADE_ASSEMBLY ("System.Security.Cryptography.Csp"),
263 	FACADE_ASSEMBLY ("System.Security.Cryptography.DeriveBytes"),
264 	FACADE_ASSEMBLY ("System.Security.Cryptography.Encoding"),
265 	FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption"),
266 	FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.Aes"),
267 	FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.ECDiffieHellman"),
268 	FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.ECDsa"),
269 	FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.Hashing"),
270 	FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.Hashing.Algorithms"),
271 	FACADE_ASSEMBLY ("System.Security.Cryptography.OpenSsl"),
272 	FACADE_ASSEMBLY ("System.Security.Cryptography.Pkcs"),
273 	FACADE_ASSEMBLY ("System.Security.Cryptography.Primitives"),
274 	FACADE_ASSEMBLY ("System.Security.Cryptography.ProtectedData"),
275 	FACADE_ASSEMBLY ("System.Security.Cryptography.RSA"),
276 	FACADE_ASSEMBLY ("System.Security.Cryptography.RandomNumberGenerator"),
277 	FACADE_ASSEMBLY ("System.Security.Cryptography.X509Certificates"),
278 	FACADE_ASSEMBLY ("System.Security.Principal"),
279 	FACADE_ASSEMBLY ("System.Security.Principal.Windows"),
280 	FACADE_ASSEMBLY ("System.Security.SecureString"),
281 	{"System.ServiceModel", 3},
282 	FACADE_ASSEMBLY ("System.ServiceModel.Duplex"),
283 	FACADE_ASSEMBLY ("System.ServiceModel.Http"),
284 	FACADE_ASSEMBLY ("System.ServiceModel.NetTcp"),
285 	FACADE_ASSEMBLY ("System.ServiceModel.Primitives"),
286 	FACADE_ASSEMBLY ("System.ServiceModel.Security"),
287 	{"System.ServiceModel.Web", 2},
288 	{"System.ServiceProcess", 0},
289 	FACADE_ASSEMBLY ("System.ServiceProcess.ServiceController"),
290 	FACADE_ASSEMBLY ("System.Text.Encoding"),
291 	FACADE_ASSEMBLY ("System.Text.Encoding.CodePages"),
292 	FACADE_ASSEMBLY ("System.Text.Encoding.Extensions"),
293 	FACADE_ASSEMBLY ("System.Text.RegularExpressions"),
294 	FACADE_ASSEMBLY ("System.Threading"),
295 	FACADE_ASSEMBLY ("System.Threading.AccessControl"),
296 	FACADE_ASSEMBLY ("System.Threading.Overlapped"),
297 	FACADE_ASSEMBLY ("System.Threading.Tasks"),
298 	FACADE_ASSEMBLY ("System.Threading.Tasks.Parallel"),
299 	FACADE_ASSEMBLY ("System.Threading.Thread"),
300 	FACADE_ASSEMBLY ("System.Threading.ThreadPool"),
301 	FACADE_ASSEMBLY ("System.Threading.Timer"),
302 	{"System.Transactions", 0},
303 	FACADE_ASSEMBLY ("System.ValueTuple"),
304 	{"System.Web", 0},
305 	{"System.Web.Abstractions", 2},
306 	{"System.Web.DynamicData", 2},
307 	{"System.Web.Extensions", 2},
308 	{"System.Web.Mobile", 0},
309 	{"System.Web.Routing", 2},
310 	{"System.Web.Services", 0},
311 	{"System.Windows", 0},
312 	{"System.Windows.Forms", 0},
313 	{"System.Xml", 0},
314 	{"System.Xml.Linq", 2},
315 	FACADE_ASSEMBLY ("System.Xml.ReaderWriter"),
316 	{"System.Xml.Serialization", 0},
317 	FACADE_ASSEMBLY ("System.Xml.XDocument"),
318 	FACADE_ASSEMBLY ("System.Xml.XPath"),
319 	FACADE_ASSEMBLY ("System.Xml.XPath.XmlDocument"),
320 	FACADE_ASSEMBLY ("System.Xml.XPath.XDocument"),
321 	FACADE_ASSEMBLY ("System.Xml.XmlDocument"),
322 	FACADE_ASSEMBLY ("System.Xml.XmlSerializer"),
323 	FACADE_ASSEMBLY ("System.Xml.Xsl.Primitives"),
324 	{"WindowsBase", 3},
325 	{"mscorlib", 0},
326 	FACADE_ASSEMBLY ("netstandard"),
327 };
328 #endif
329 
330 /*
331  * keeps track of loaded assemblies
332  */
333 static GList *loaded_assemblies = NULL;
334 static MonoAssembly *corlib;
335 
336 static char* unquote (const char *str);
337 
338 /* This protects loaded_assemblies and image->references */
339 #define mono_assemblies_lock() mono_os_mutex_lock (&assemblies_mutex)
340 #define mono_assemblies_unlock() mono_os_mutex_unlock (&assemblies_mutex)
341 static mono_mutex_t assemblies_mutex;
342 
343 /* If defined, points to the bundled assembly information */
344 const MonoBundledAssembly **bundles;
345 
346 static mono_mutex_t assembly_binding_mutex;
347 
348 /* Loaded assembly binding info */
349 static GSList *loaded_assembly_bindings = NULL;
350 
351 /* Class lazy loading functions */
352 static GENERATE_TRY_GET_CLASS_WITH_CACHE (internals_visible, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute")
353 static MonoAssembly*
354 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload);
355 static MonoAssembly*
356 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly);
357 static MonoBoolean
358 mono_assembly_is_in_gac (const gchar *filanem);
359 
360 static MonoAssembly*
361 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly);
362 
363 static gboolean
364 assembly_names_equal_flags (MonoAssemblyName *l, MonoAssemblyName *r, AssemblyNameEqFlags flags);
365 
366 /* Assembly name matching */
367 static gboolean
368 exact_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name);
369 static gboolean
370 framework_assembly_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name);
371 
372 static gchar*
encode_public_tok(const guchar * token,gint32 len)373 encode_public_tok (const guchar *token, gint32 len)
374 {
375 	const static gchar allowed [] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
376 	gchar *res;
377 	int i;
378 
379 	res = (gchar *)g_malloc (len * 2 + 1);
380 	for (i = 0; i < len; i++) {
381 		res [i * 2] = allowed [token [i] >> 4];
382 		res [i * 2 + 1] = allowed [token [i] & 0xF];
383 	}
384 	res [len * 2] = 0;
385 	return res;
386 }
387 
388 /**
389  * mono_public_tokens_are_equal:
390  * \param pubt1 first public key token
391  * \param pubt2 second public key token
392  *
393  * Compare two public key tokens and return TRUE is they are equal and FALSE
394  * otherwise.
395  */
396 gboolean
mono_public_tokens_are_equal(const unsigned char * pubt1,const unsigned char * pubt2)397 mono_public_tokens_are_equal (const unsigned char *pubt1, const unsigned char *pubt2)
398 {
399 	return memcmp (pubt1, pubt2, 16) == 0;
400 }
401 
402 /**
403  * mono_set_assemblies_path:
404  * \param path list of paths that contain directories where Mono will look for assemblies
405  *
406  * Use this method to override the standard assembly lookup system and
407  * override any assemblies coming from the GAC.  This is the method
408  * that supports the \c MONO_PATH variable.
409  *
410  * Notice that \c MONO_PATH and this method are really a very bad idea as
411  * it prevents the GAC from working and it prevents the standard
412  * resolution mechanisms from working.  Nonetheless, for some debugging
413  * situations and bootstrapping setups, this is useful to have.
414  */
415 void
mono_set_assemblies_path(const char * path)416 mono_set_assemblies_path (const char* path)
417 {
418 	char **splitted, **dest;
419 
420 	splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
421 	if (assemblies_path)
422 		g_strfreev (assemblies_path);
423 	assemblies_path = dest = splitted;
424 	while (*splitted) {
425 		char *tmp = *splitted;
426 		if (*tmp)
427 			*dest++ = mono_path_canonicalize (tmp);
428 		g_free (tmp);
429 		splitted++;
430 	}
431 	*dest = *splitted;
432 
433 	if (g_hasenv ("MONO_DEBUG"))
434 		return;
435 
436 	splitted = assemblies_path;
437 	while (*splitted) {
438 		if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
439 			g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted);
440 
441 		splitted++;
442 	}
443 }
444 
445 static void
check_path_env(void)446 check_path_env (void)
447 {
448 	if (assemblies_path != NULL)
449 		return;
450 
451 	char* path = g_getenv ("MONO_PATH");
452 	if (!path)
453 		return;
454 
455 	mono_set_assemblies_path(path);
456 	g_free (path);
457 }
458 
459 static void
check_extra_gac_path_env(void)460 check_extra_gac_path_env (void)
461 {
462 	char *path;
463 	char **splitted, **dest;
464 
465 	path = g_getenv ("MONO_GAC_PREFIX");
466 	if (!path)
467 		return;
468 
469 	splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
470 	g_free (path);
471 
472 	if (extra_gac_paths)
473 		g_strfreev (extra_gac_paths);
474 	extra_gac_paths = dest = splitted;
475 	while (*splitted){
476 		if (**splitted)
477 			*dest++ = *splitted;
478 		splitted++;
479 	}
480 	*dest = *splitted;
481 
482 	if (!g_hasenv ("MONO_DEBUG"))
483 		return;
484 
485 	while (*splitted) {
486 		if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
487 			g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted);
488 
489 		splitted++;
490 	}
491 }
492 
493 static gboolean
assembly_binding_maps_name(MonoAssemblyBindingInfo * info,MonoAssemblyName * aname)494 assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
495 {
496 	if (!info || !info->name)
497 		return FALSE;
498 
499 	if (strcmp (info->name, aname->name))
500 		return FALSE;
501 
502 	if (info->major != aname->major || info->minor != aname->minor)
503 		return FALSE;
504 
505 	if ((info->culture != NULL && info->culture [0]) != (aname->culture != NULL && aname->culture [0]))
506 		return FALSE;
507 
508 	if (info->culture && aname->culture && strcmp (info->culture, aname->culture))
509 		return FALSE;
510 
511 	if (!mono_public_tokens_are_equal (info->public_key_token, aname->public_key_token))
512 		return FALSE;
513 
514 	return TRUE;
515 }
516 
517 static void
mono_assembly_binding_info_free(MonoAssemblyBindingInfo * info)518 mono_assembly_binding_info_free (MonoAssemblyBindingInfo *info)
519 {
520 	if (!info)
521 		return;
522 
523 	g_free (info->name);
524 	g_free (info->culture);
525 }
526 
527 static void
get_publisher_policy_info(MonoImage * image,MonoAssemblyName * aname,MonoAssemblyBindingInfo * binding_info)528 get_publisher_policy_info (MonoImage *image, MonoAssemblyName *aname, MonoAssemblyBindingInfo *binding_info)
529 {
530 	MonoTableInfo *t;
531 	guint32 cols [MONO_MANIFEST_SIZE];
532 	const gchar *filename;
533 	gchar *subpath, *fullpath;
534 
535 	t = &image->tables [MONO_TABLE_MANIFESTRESOURCE];
536 	/* MS Impl. accepts policy assemblies with more than
537 	 * one manifest resource, and only takes the first one */
538 	if (t->rows < 1) {
539 		binding_info->is_valid = FALSE;
540 		return;
541 	}
542 
543 	mono_metadata_decode_row (t, 0, cols, MONO_MANIFEST_SIZE);
544 	if ((cols [MONO_MANIFEST_IMPLEMENTATION] & MONO_IMPLEMENTATION_MASK) != MONO_IMPLEMENTATION_FILE) {
545 		binding_info->is_valid = FALSE;
546 		return;
547 	}
548 
549 	filename = mono_metadata_string_heap (image, cols [MONO_MANIFEST_NAME]);
550 	g_assert (filename != NULL);
551 
552 	subpath = g_path_get_dirname (image->name);
553 	fullpath = g_build_path (G_DIR_SEPARATOR_S, subpath, filename, NULL);
554 	mono_config_parse_publisher_policy (fullpath, binding_info);
555 	g_free (subpath);
556 	g_free (fullpath);
557 
558 	/* Define the optional elements/attributes before checking */
559 	if (!binding_info->culture)
560 		binding_info->culture = g_strdup ("");
561 
562 	/* Check that the most important elements/attributes exist */
563 	if (!binding_info->name || !binding_info->public_key_token [0] || !binding_info->has_old_version_bottom ||
564 			!binding_info->has_new_version || !assembly_binding_maps_name (binding_info, aname)) {
565 		mono_assembly_binding_info_free (binding_info);
566 		binding_info->is_valid = FALSE;
567 		return;
568 	}
569 
570 	binding_info->is_valid = TRUE;
571 }
572 
573 static int
compare_versions(AssemblyVersionSet * v,MonoAssemblyName * aname)574 compare_versions (AssemblyVersionSet *v, MonoAssemblyName *aname)
575 {
576 	if (v->major > aname->major)
577 		return 1;
578 	else if (v->major < aname->major)
579 		return -1;
580 
581 	if (v->minor > aname->minor)
582 		return 1;
583 	else if (v->minor < aname->minor)
584 		return -1;
585 
586 	if (v->build > aname->build)
587 		return 1;
588 	else if (v->build < aname->build)
589 		return -1;
590 
591 	if (v->revision > aname->revision)
592 		return 1;
593 	else if (v->revision < aname->revision)
594 		return -1;
595 
596 	return 0;
597 }
598 
599 static gboolean
check_policy_versions(MonoAssemblyBindingInfo * info,MonoAssemblyName * name)600 check_policy_versions (MonoAssemblyBindingInfo *info, MonoAssemblyName *name)
601 {
602 	if (!info->is_valid)
603 		return FALSE;
604 
605 	/* If has_old_version_top doesn't exist, we don't have an interval */
606 	if (!info->has_old_version_top) {
607 		if (compare_versions (&info->old_version_bottom, name) == 0)
608 			return TRUE;
609 
610 		return FALSE;
611 	}
612 
613 	/* Check that the version defined by name is valid for the interval */
614 	if (compare_versions (&info->old_version_top, name) < 0)
615 		return FALSE;
616 
617 	/* We should be greater or equal than the small version */
618 	if (compare_versions (&info->old_version_bottom, name) > 0)
619 		return FALSE;
620 
621 	return TRUE;
622 }
623 
624 /**
625  * mono_assembly_names_equal:
626  * \param l first assembly
627  * \param r second assembly.
628  *
629  * Compares two \c MonoAssemblyName instances and returns whether they are equal.
630  *
631  * This compares the names, the cultures, the release version and their
632  * public tokens.
633  *
634  * \returns TRUE if both assembly names are equal.
635  */
636 gboolean
mono_assembly_names_equal(MonoAssemblyName * l,MonoAssemblyName * r)637 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
638 {
639 	return assembly_names_equal_flags (l, r, ANAME_EQ_NONE);
640 }
641 
642 gboolean
assembly_names_equal_flags(MonoAssemblyName * l,MonoAssemblyName * r,AssemblyNameEqFlags flags)643 assembly_names_equal_flags (MonoAssemblyName *l, MonoAssemblyName *r, AssemblyNameEqFlags flags)
644 {
645 	if (!l->name || !r->name)
646 		return FALSE;
647 
648 	if (strcmp (l->name, r->name))
649 		return FALSE;
650 
651 	if (l->culture && r->culture && strcmp (l->culture, r->culture))
652 		return FALSE;
653 
654 	if ((l->major != r->major || l->minor != r->minor ||
655 	     l->build != r->build || l->revision != r->revision) &&
656 	    (flags & ANAME_EQ_IGNORE_VERSION) == 0)
657 		if (! ((l->major == 0 && l->minor == 0 && l->build == 0 && l->revision == 0) || (r->major == 0 && r->minor == 0 && r->build == 0 && r->revision == 0)))
658 			return FALSE;
659 
660 	if (!l->public_key_token [0] || !r->public_key_token [0] || (flags & ANAME_EQ_IGNORE_PUBKEY) != 0)
661 		return TRUE;
662 
663 	if (!mono_public_tokens_are_equal (l->public_key_token, r->public_key_token))
664 		return FALSE;
665 
666 	return TRUE;
667 }
668 
669 static MonoAssembly *
load_in_path(const char * basename,const char ** search_path,MonoImageOpenStatus * status,MonoBoolean refonly,MonoAssemblyCandidatePredicate predicate,gpointer user_data)670 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly, MonoAssemblyCandidatePredicate predicate, gpointer user_data)
671 {
672 	int i;
673 	char *fullpath;
674 	MonoAssembly *result;
675 
676 	for (i = 0; search_path [i]; ++i) {
677 		fullpath = g_build_filename (search_path [i], basename, NULL);
678 		result = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, user_data, status);
679 		g_free (fullpath);
680 		if (result)
681 			return result;
682 	}
683 	return NULL;
684 }
685 
686 /**
687  * mono_assembly_setrootdir:
688  * \param root_dir The pathname of the root directory where we will locate assemblies
689  *
690  * This routine sets the internal default root directory for looking up
691  * assemblies.
692  *
693  * This is used by Windows installations to compute dynamically the
694  * place where the Mono assemblies are located.
695  *
696  */
697 void
mono_assembly_setrootdir(const char * root_dir)698 mono_assembly_setrootdir (const char *root_dir)
699 {
700 	/*
701 	 * Override the MONO_ASSEMBLIES directory configured at compile time.
702 	 */
703 	/* Leak if called more than once */
704 	default_path [0] = g_strdup (root_dir);
705 }
706 
707 /**
708  * mono_assembly_getrootdir:
709  *
710  * Obtains the root directory used for looking up assemblies.
711  *
712  * Returns: a string with the directory, this string should not be freed.
713  */
714 G_CONST_RETURN gchar *
mono_assembly_getrootdir(void)715 mono_assembly_getrootdir (void)
716 {
717 	return default_path [0];
718 }
719 
720 /**
721  * mono_native_getrootdir:
722  *
723  * Obtains the root directory used for looking up native libs (.so, .dylib).
724  *
725  * Returns: a string with the directory, this string should be freed by
726  * the caller.
727  */
728 gchar *
mono_native_getrootdir(void)729 mono_native_getrootdir (void)
730 {
731 	gchar* fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), mono_config_get_reloc_lib_dir(), NULL);
732 	return fullpath;
733 }
734 
735 /**
736  * mono_set_dirs:
737  * \param assembly_dir the base directory for assemblies
738  * \param config_dir the base directory for configuration files
739  *
740  * This routine is used internally and by developers embedding
741  * the runtime into their own applications.
742  *
743  * There are a number of cases to consider: Mono as a system-installed
744  * package that is available on the location preconfigured or Mono in
745  * a relocated location.
746  *
747  * If you are using a system-installed Mono, you can pass NULL
748  * to both parameters.  If you are not, you should compute both
749  * directory values and call this routine.
750  *
751  * The values for a given PREFIX are:
752  *
753  *    assembly_dir: PREFIX/lib
754  *    config_dir:   PREFIX/etc
755  *
756  * Notice that embedders that use Mono in a relocated way must
757  * compute the location at runtime, as they will be in control
758  * of where Mono is installed.
759  */
760 void
mono_set_dirs(const char * assembly_dir,const char * config_dir)761 mono_set_dirs (const char *assembly_dir, const char *config_dir)
762 {
763 	if (assembly_dir == NULL)
764 		assembly_dir = mono_config_get_assemblies_dir ();
765 	if (config_dir == NULL)
766 		config_dir = mono_config_get_cfg_dir ();
767 	mono_assembly_setrootdir (assembly_dir);
768 	mono_set_config_dir (config_dir);
769 }
770 
771 #ifndef HOST_WIN32
772 
773 static char *
compute_base(char * path)774 compute_base (char *path)
775 {
776 	char *p = strrchr (path, '/');
777 	if (p == NULL)
778 		return NULL;
779 
780 	/* Not a well known Mono executable, we are embedded, cant guess the base  */
781 	if (strcmp (p, "/mono") && strcmp (p, "/mono-boehm") && strcmp (p, "/mono-sgen") && strcmp (p, "/pedump") && strcmp (p, "/monodis"))
782 		return NULL;
783 
784 	*p = 0;
785 	p = strrchr (path, '/');
786 	if (p == NULL)
787 		return NULL;
788 
789 	if (strcmp (p, "/bin") != 0)
790 		return NULL;
791 	*p = 0;
792 	return path;
793 }
794 
795 static void
fallback(void)796 fallback (void)
797 {
798 	mono_set_dirs (mono_config_get_assemblies_dir (), mono_config_get_cfg_dir ());
799 }
800 
801 static G_GNUC_UNUSED void
set_dirs(char * exe)802 set_dirs (char *exe)
803 {
804 	char *base;
805 	char *config, *lib, *mono;
806 	struct stat buf;
807 	const char *bindir;
808 
809 	/*
810 	 * Only /usr prefix is treated specially
811 	 */
812 	bindir = mono_config_get_bin_dir ();
813 	g_assert (bindir);
814 	if (strncmp (exe, bindir, strlen (bindir)) == 0 || (base = compute_base (exe)) == NULL){
815 		fallback ();
816 		return;
817 	}
818 
819 	config = g_build_filename (base, "etc", NULL);
820 	lib = g_build_filename (base, "lib", NULL);
821 	mono = g_build_filename (lib, "mono/4.5", NULL);  // FIXME: stop hardcoding 4.5 here
822 	if (stat (mono, &buf) == -1)
823 		fallback ();
824 	else {
825 		mono_set_dirs (lib, config);
826 	}
827 
828 	g_free (config);
829 	g_free (lib);
830 	g_free (mono);
831 }
832 
833 #endif /* HOST_WIN32 */
834 
835 /**
836  * mono_set_rootdir:
837  *
838  * Registers the root directory for the Mono runtime, for Linux and Solaris 10,
839  * this auto-detects the prefix where Mono was installed.
840  */
841 void
mono_set_rootdir(void)842 mono_set_rootdir (void)
843 {
844 #if defined(HOST_WIN32) || (defined(HOST_DARWIN) && !defined(TARGET_ARM))
845 	gchar *bindir, *installdir, *root, *name, *resolvedname, *config;
846 
847 #ifdef HOST_WIN32
848 	name = mono_get_module_file_name ((HMODULE) &__ImageBase);
849 #else
850  	{
851 		/*
852 		 * _NSGetExecutablePath may return -1 to indicate buf is not large
853 		 *  enough, but we ignore that case to avoid having to do extra dynamic
854 		 *  allocation for the path and hope that 4096 is enough - this is
855 		 *  ok in the Linux/Solaris case below at least...
856 		 */
857 
858 		gchar buf[4096];
859  		guint buf_size = sizeof (buf);
860 
861 		name = NULL;
862  		if (_NSGetExecutablePath (buf, &buf_size) == 0)
863  			name = g_strdup (buf);
864 
865  		if (name == NULL) {
866  			fallback ();
867  			return;
868  		}
869  	}
870 #endif
871 
872 	resolvedname = mono_path_resolve_symlinks (name);
873 
874 	bindir = g_path_get_dirname (resolvedname);
875 	installdir = g_path_get_dirname (bindir);
876 	root = g_build_path (G_DIR_SEPARATOR_S, installdir, "lib", NULL);
877 
878 	config = g_build_filename (root, "..", "etc", NULL);
879 #ifdef HOST_WIN32
880 	mono_set_dirs (root, config);
881 #else
882 	if (g_file_test (root, G_FILE_TEST_EXISTS) && g_file_test (config, G_FILE_TEST_EXISTS))
883 		mono_set_dirs (root, config);
884 	else
885 		fallback ();
886 #endif
887 
888 	g_free (config);
889 	g_free (root);
890 	g_free (installdir);
891 	g_free (bindir);
892 	g_free (name);
893 	g_free (resolvedname);
894 #elif defined(DISABLE_MONO_AUTODETECTION)
895 	fallback ();
896 #else
897 	char buf [4096];
898 	int  s;
899 	char *str;
900 
901 	/* Linux style */
902 	s = readlink ("/proc/self/exe", buf, sizeof (buf)-1);
903 
904 	if (s != -1){
905 		buf [s] = 0;
906 		set_dirs (buf);
907 		return;
908 	}
909 
910 	/* Solaris 10 style */
911 	str = g_strdup_printf ("/proc/%d/path/a.out", getpid ());
912 	s = readlink (str, buf, sizeof (buf)-1);
913 	g_free (str);
914 	if (s != -1){
915 		buf [s] = 0;
916 		set_dirs (buf);
917 		return;
918 	}
919 	fallback ();
920 #endif
921 }
922 
923 /**
924  * mono_assemblies_init:
925  *
926  *  Initialize global variables used by this module.
927  */
928 void
mono_assemblies_init(void)929 mono_assemblies_init (void)
930 {
931 	/*
932 	 * Initialize our internal paths if we have not been initialized yet.
933 	 * This happens when embedders use Mono.
934 	 */
935 	if (mono_assembly_getrootdir () == NULL)
936 		mono_set_rootdir ();
937 
938 	check_path_env ();
939 	check_extra_gac_path_env ();
940 
941 	mono_os_mutex_init_recursive (&assemblies_mutex);
942 	mono_os_mutex_init (&assembly_binding_mutex);
943 
944 #ifndef DISABLE_DESKTOP_LOADER
945 	assembly_remapping_table = g_hash_table_new (g_str_hash, g_str_equal);
946 
947 	int i;
948 	for (i = 0; i < G_N_ELEMENTS (framework_assemblies) - 1; ++i)
949 		g_hash_table_insert (assembly_remapping_table, (void*)framework_assemblies [i].assembly_name, (void*)&framework_assemblies [i]);
950 
951 #endif
952 }
953 
954 static void
mono_assembly_binding_lock(void)955 mono_assembly_binding_lock (void)
956 {
957 	mono_locks_os_acquire (&assembly_binding_mutex, AssemblyBindingLock);
958 }
959 
960 static void
mono_assembly_binding_unlock(void)961 mono_assembly_binding_unlock (void)
962 {
963 	mono_locks_os_release (&assembly_binding_mutex, AssemblyBindingLock);
964 }
965 
966 gboolean
mono_assembly_fill_assembly_name_full(MonoImage * image,MonoAssemblyName * aname,gboolean copyBlobs)967 mono_assembly_fill_assembly_name_full (MonoImage *image, MonoAssemblyName *aname, gboolean copyBlobs)
968 {
969 	MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
970 	guint32 cols [MONO_ASSEMBLY_SIZE];
971 	gint32 machine, flags;
972 
973 	if (!t->rows)
974 		return FALSE;
975 
976 	mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
977 
978 	aname->hash_len = 0;
979 	aname->hash_value = NULL;
980 	aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
981 	if (copyBlobs)
982 		aname->name = g_strdup (aname->name);
983 	aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
984 	if (copyBlobs)
985 		aname->culture = g_strdup (aname->culture);
986 	aname->flags = cols [MONO_ASSEMBLY_FLAGS];
987 	aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
988 	aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
989 	aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
990 	aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
991 	aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
992 	if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
993 		guchar* token = (guchar *)g_malloc (8);
994 		gchar* encoded;
995 		const gchar* pkey;
996 		int len;
997 
998 		pkey = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
999 		len = mono_metadata_decode_blob_size (pkey, &pkey);
1000 		aname->public_key = (guchar*)pkey;
1001 
1002 		mono_digest_get_public_token (token, aname->public_key, len);
1003 		encoded = encode_public_tok (token, 8);
1004 		g_strlcpy ((char*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1005 
1006 		g_free (encoded);
1007 		g_free (token);
1008 	}
1009 	else {
1010 		aname->public_key = NULL;
1011 		memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1012 	}
1013 
1014 	if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
1015 		aname->public_key = (guchar*)mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
1016 		if (copyBlobs) {
1017 			const gchar *pkey_end;
1018 			int len = mono_metadata_decode_blob_size ((const gchar*) aname->public_key, &pkey_end);
1019 			pkey_end += len; /* move to end */
1020 			size_t size = pkey_end - (const gchar*)aname->public_key;
1021 			guchar *tmp = g_new (guchar, size);
1022 			memcpy (tmp, aname->public_key, size);
1023 			aname->public_key = tmp;
1024 		}
1025 
1026 	}
1027 	else
1028 		aname->public_key = 0;
1029 
1030 	machine = ((MonoCLIImageInfo*)(image->image_info))->cli_header.coff.coff_machine;
1031 	flags = ((MonoCLIImageInfo*)(image->image_info))->cli_cli_header.ch_flags;
1032 	switch (machine) {
1033 	case COFF_MACHINE_I386:
1034 		/* https://bugzilla.xamarin.com/show_bug.cgi?id=17632 */
1035 		if (flags & (CLI_FLAGS_32BITREQUIRED|CLI_FLAGS_PREFERRED32BIT))
1036 			aname->arch = MONO_PROCESSOR_ARCHITECTURE_X86;
1037 		else if ((flags & 0x70) == 0x70)
1038 			aname->arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
1039 		else
1040 			aname->arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
1041 		break;
1042 	case COFF_MACHINE_IA64:
1043 		aname->arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
1044 		break;
1045 	case COFF_MACHINE_AMD64:
1046 		aname->arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
1047 		break;
1048 	case COFF_MACHINE_ARM:
1049 		aname->arch = MONO_PROCESSOR_ARCHITECTURE_ARM;
1050 		break;
1051 	default:
1052 		break;
1053 	}
1054 
1055 	return TRUE;
1056 }
1057 
1058 /**
1059  * mono_assembly_fill_assembly_name:
1060  * \param image Image
1061  * \param aname Name
1062  * \returns TRUE if successful
1063  */
1064 gboolean
mono_assembly_fill_assembly_name(MonoImage * image,MonoAssemblyName * aname)1065 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
1066 {
1067 	return mono_assembly_fill_assembly_name_full (image, aname, FALSE);
1068 }
1069 
1070 /**
1071  * mono_stringify_assembly_name:
1072  * \param aname the assembly name.
1073  *
1074  * Convert \p aname into its string format. The returned string is dynamically
1075  * allocated and should be freed by the caller.
1076  *
1077  * \returns a newly allocated string with a string representation of
1078  * the assembly name.
1079  */
1080 char*
mono_stringify_assembly_name(MonoAssemblyName * aname)1081 mono_stringify_assembly_name (MonoAssemblyName *aname)
1082 {
1083 	const char *quote = (aname->name && g_ascii_isspace (aname->name [0])) ? "\"" : "";
1084 
1085 	return g_strdup_printf (
1086 		"%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
1087 		quote, aname->name, quote,
1088 		aname->major, aname->minor, aname->build, aname->revision,
1089 		aname->culture && *aname->culture? aname->culture: "neutral",
1090 		aname->public_key_token [0] ? (char *)aname->public_key_token : "null",
1091 		(aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
1092 }
1093 
1094 static gchar*
assemblyref_public_tok(MonoImage * image,guint32 key_index,guint32 flags)1095 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
1096 {
1097 	const gchar *public_tok;
1098 	int len;
1099 
1100 	public_tok = mono_metadata_blob_heap (image, key_index);
1101 	len = mono_metadata_decode_blob_size (public_tok, &public_tok);
1102 
1103 	if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
1104 		guchar token [8];
1105 		mono_digest_get_public_token (token, (guchar*)public_tok, len);
1106 		return encode_public_tok (token, 8);
1107 	}
1108 
1109 	return encode_public_tok ((guchar*)public_tok, len);
1110 }
1111 
1112 /**
1113  * mono_assembly_addref:
1114  * \param assembly the assembly to reference
1115  *
1116  * This routine increments the reference count on a MonoAssembly.
1117  * The reference count is reduced every time the method mono_assembly_close() is
1118  * invoked.
1119  */
1120 void
mono_assembly_addref(MonoAssembly * assembly)1121 mono_assembly_addref (MonoAssembly *assembly)
1122 {
1123 	mono_atomic_inc_i32 (&assembly->ref_count);
1124 }
1125 
1126 /*
1127  * CAUTION: This table must be kept in sync with
1128  *          ivkm/reflect/Fusion.cs
1129  */
1130 
1131 #define SILVERLIGHT_KEY "7cec85d7bea7798e"
1132 #define WINFX_KEY "31bf3856ad364e35"
1133 #define ECMA_KEY "b77a5c561934e089"
1134 #define MSFINAL_KEY "b03f5f7f11d50a3a"
1135 #define COMPACTFRAMEWORK_KEY "969db8053d3322ac"
1136 
1137 typedef struct {
1138 	const char *name;
1139 	const char *from;
1140 	const char *to;
1141 } KeyRemapEntry;
1142 
1143 static KeyRemapEntry key_remap_table[] = {
1144 	{ "CustomMarshalers", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1145 	{ "Microsoft.CSharp", WINFX_KEY, MSFINAL_KEY },
1146 	{ "Microsoft.VisualBasic", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1147 	{ "System", SILVERLIGHT_KEY, ECMA_KEY },
1148 	{ "System", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1149 	{ "System.ComponentModel.Composition", WINFX_KEY, ECMA_KEY },
1150 	{ "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY },
1151 	{ "System.Core", SILVERLIGHT_KEY, ECMA_KEY },
1152 	{ "System.Core", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1153 	{ "System.Data", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1154 	{ "System.Data.DataSetExtensions", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1155 	{ "System.Drawing", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1156 	{ "System.Messaging", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1157 	// FIXME: MS uses MSFINAL_KEY for .NET 4.5
1158 	{ "System.Net", SILVERLIGHT_KEY, MSFINAL_KEY },
1159 	{ "System.Numerics", WINFX_KEY, ECMA_KEY },
1160 	{ "System.Runtime.Serialization", SILVERLIGHT_KEY, ECMA_KEY },
1161 	{ "System.Runtime.Serialization", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1162 	{ "System.ServiceModel", WINFX_KEY, ECMA_KEY },
1163 	{ "System.ServiceModel", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1164 	{ "System.ServiceModel.Web", SILVERLIGHT_KEY, WINFX_KEY },
1165 	{ "System.Web.Services", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1166 	{ "System.Windows", SILVERLIGHT_KEY, MSFINAL_KEY },
1167 	{ "System.Windows.Forms", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1168 	{ "System.Xml", SILVERLIGHT_KEY, ECMA_KEY },
1169 	{ "System.Xml", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1170 	{ "System.Xml.Linq", WINFX_KEY, ECMA_KEY },
1171 	{ "System.Xml.Linq", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1172 	{ "System.Xml.Serialization", WINFX_KEY, ECMA_KEY }
1173 };
1174 
1175 static void
remap_keys(MonoAssemblyName * aname)1176 remap_keys (MonoAssemblyName *aname)
1177 {
1178 	int i;
1179 	for (i = 0; i < G_N_ELEMENTS (key_remap_table); i++) {
1180 		const KeyRemapEntry *entry = &key_remap_table [i];
1181 
1182 		if (strcmp (aname->name, entry->name) ||
1183 		    !mono_public_tokens_are_equal (aname->public_key_token, (const unsigned char*) entry->from))
1184 			continue;
1185 
1186 		memcpy (aname->public_key_token, entry->to, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1187 
1188 		mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1189 			    "Remapped public key token of retargetable assembly %s from %s to %s",
1190 			    aname->name, entry->from, entry->to);
1191 		return;
1192 	}
1193 }
1194 
1195 static MonoAssemblyName *
mono_assembly_remap_version(MonoAssemblyName * aname,MonoAssemblyName * dest_aname)1196 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
1197 {
1198 	const MonoRuntimeInfo *current_runtime;
1199 
1200 	if (aname->name == NULL) return aname;
1201 
1202 	current_runtime = mono_get_runtime_info ();
1203 
1204 	if (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) {
1205 		const AssemblyVersionSet* vset;
1206 
1207 		/* Remap to current runtime */
1208 		vset = &current_runtime->version_sets [0];
1209 
1210 		memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1211 		dest_aname->major = vset->major;
1212 		dest_aname->minor = vset->minor;
1213 		dest_aname->build = vset->build;
1214 		dest_aname->revision = vset->revision;
1215 		dest_aname->flags &= ~ASSEMBLYREF_RETARGETABLE_FLAG;
1216 
1217 		/* Remap assembly name */
1218 		if (!strcmp (aname->name, "System.Net"))
1219 			dest_aname->name = g_strdup ("System");
1220 
1221 		remap_keys (dest_aname);
1222 
1223 		mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1224 					"The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
1225 					aname->name,
1226 					aname->major, aname->minor, aname->build, aname->revision,
1227 					dest_aname->name,
1228 					vset->major, vset->minor, vset->build, vset->revision
1229 					);
1230 
1231 		return dest_aname;
1232 	}
1233 
1234 #ifndef DISABLE_DESKTOP_LOADER
1235 	const AssemblyVersionMap *vmap = (AssemblyVersionMap *)g_hash_table_lookup (assembly_remapping_table, aname->name);
1236 	if (vmap) {
1237 		const AssemblyVersionSet* vset;
1238 		int index = vmap->version_set_index;
1239 		g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
1240 		vset = &current_runtime->version_sets [index];
1241 
1242 		if (vmap->framework_facade_assembly) {
1243 			mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Assembly %s is a framework Facade asseembly",
1244 				    aname->name);
1245 			return aname;
1246 		}
1247 
1248 		if (aname->major == vset->major && aname->minor == vset->minor &&
1249 			aname->build == vset->build && aname->revision == vset->revision) {
1250 			mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Found assembly remapping for %s and was for the same version %d.%d.%d.%d",
1251 				aname->name,
1252 				aname->major, aname->minor, aname->build, aname->revision);
1253 			return aname;
1254 		}
1255 
1256 		if (vmap->only_lower_versions && compare_versions ((AssemblyVersionSet*)vset, aname) < 0) {
1257 			mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY,
1258 				"Found lower-versions-only assembly remaping to load %s %d.%d.%d.%d but mapping has %d.%d.%d.%d",
1259 						aname->name,
1260 						aname->major, aname->minor, aname->build, aname->revision,
1261 						vset->major, vset->minor, vset->build, vset->revision
1262 						);
1263 			return aname;
1264 		}
1265 
1266 		if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
1267 			mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1268 				"The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
1269 						aname->name,
1270 						aname->major, aname->minor, aname->build, aname->revision,
1271 						vset->major, vset->minor, vset->build, vset->revision
1272 						);
1273 
1274 		memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1275 		dest_aname->major = vset->major;
1276 		dest_aname->minor = vset->minor;
1277 		dest_aname->build = vset->build;
1278 		dest_aname->revision = vset->revision;
1279 		if (vmap->new_assembly_name != NULL) {
1280 			dest_aname->name = vmap->new_assembly_name;
1281 			mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1282 						"The assembly name %s was remapped to %s",
1283 						aname->name,
1284 						dest_aname->name);
1285 		}
1286 		return dest_aname;
1287 	}
1288 #endif
1289 
1290 	return aname;
1291 }
1292 
1293 /**
1294  * mono_assembly_get_assemblyref:
1295  * \param image pointer to the \c MonoImage to extract the information from.
1296  * \param index index to the assembly reference in the image.
1297  * \param aname pointer to a \c MonoAssemblyName that will hold the returned value.
1298  *
1299  * Fills out the \p aname with the assembly name of the \p index assembly reference in \p image.
1300  */
1301 void
mono_assembly_get_assemblyref(MonoImage * image,int index,MonoAssemblyName * aname)1302 mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *aname)
1303 {
1304 	MonoTableInfo *t;
1305 	guint32 cols [MONO_ASSEMBLYREF_SIZE];
1306 	const char *hash;
1307 
1308 	t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1309 
1310 	mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
1311 
1312 	hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
1313 	aname->hash_len = mono_metadata_decode_blob_size (hash, &hash);
1314 	aname->hash_value = hash;
1315 	aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
1316 	aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
1317 	aname->flags = cols [MONO_ASSEMBLYREF_FLAGS];
1318 	aname->major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
1319 	aname->minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
1320 	aname->build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
1321 	aname->revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
1322 
1323 	if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
1324 		gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
1325 		g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1326 		g_free (token);
1327 	} else {
1328 		memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1329 	}
1330 }
1331 
1332 /**
1333  * mono_assembly_load_reference:
1334  */
1335 void
mono_assembly_load_reference(MonoImage * image,int index)1336 mono_assembly_load_reference (MonoImage *image, int index)
1337 {
1338 	MonoAssembly *reference;
1339 	MonoAssemblyName aname;
1340 	MonoImageOpenStatus status;
1341 
1342 	/*
1343 	 * image->references is shared between threads, so we need to access
1344 	 * it inside a critical section.
1345 	 */
1346 	mono_assemblies_lock ();
1347 	if (!image->references) {
1348 		MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1349 
1350 		image->references = g_new0 (MonoAssembly *, t->rows + 1);
1351 		image->nreferences = t->rows;
1352 	}
1353 	reference = image->references [index];
1354 	mono_assemblies_unlock ();
1355 	if (reference)
1356 		return;
1357 
1358 	mono_assembly_get_assemblyref (image, index, &aname);
1359 
1360 	if (image->assembly && image->assembly->ref_only) {
1361 		/* We use the loaded corlib */
1362 		if (!strcmp (aname.name, "mscorlib"))
1363 			reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1364 		else {
1365 			reference = mono_assembly_loaded_full (&aname, TRUE);
1366 			if (!reference)
1367 				/* Try a postload search hook */
1368 				reference = mono_assembly_invoke_search_hook_internal (&aname, image->assembly, TRUE, TRUE);
1369 		}
1370 
1371 		/*
1372 		 * Here we must advice that the error was due to
1373 		 * a non loaded reference using the ReflectionOnly api
1374 		*/
1375 		if (!reference)
1376 			reference = (MonoAssembly *)REFERENCE_MISSING;
1377 	} else {
1378 		/* we first try without setting the basedir: this can eventually result in a ResolveAssembly
1379 		 * event which is the MS .net compatible behaviour (the assemblyresolve_event3.cs test has been fixed
1380 		 * accordingly, it would fail on the MS runtime before).
1381 		 * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
1382 		 * example bug-349190.2.cs and who knows how much more code in the wild.
1383 		 */
1384 		reference = mono_assembly_load_full_internal (&aname, image->assembly, NULL, &status, FALSE);
1385 		if (!reference && image->assembly)
1386 			reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1387 	}
1388 
1389 	if (reference == NULL){
1390 		char *extra_msg;
1391 
1392 		if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
1393 			extra_msg = g_strdup_printf ("The assembly was not found in the Global Assembly Cache, a path listed in the MONO_PATH environment variable, or in the location of the executing assembly (%s).\n", image->assembly != NULL ? image->assembly->basedir : "" );
1394 		} else if (status == MONO_IMAGE_ERROR_ERRNO) {
1395 			extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
1396 		} else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
1397 			extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
1398 		} else if (status == MONO_IMAGE_IMAGE_INVALID) {
1399 			extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
1400 		} else {
1401 			extra_msg = g_strdup ("");
1402 		}
1403 
1404 		mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n"
1405 				   "     Assembly:   %s    (assemblyref_index=%d)\n"
1406 				   "     Version:    %d.%d.%d.%d\n"
1407 				   "     Public Key: %s\n%s",
1408 				   image->name, aname.name, index,
1409 				   aname.major, aname.minor, aname.build, aname.revision,
1410 				   strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
1411 		g_free (extra_msg);
1412 
1413 	}
1414 
1415 	mono_assemblies_lock ();
1416 	if (reference == NULL) {
1417 		/* Flag as not found */
1418 		reference = (MonoAssembly *)REFERENCE_MISSING;
1419 	}
1420 
1421 	if (!image->references [index]) {
1422 		if (reference != REFERENCE_MISSING){
1423 			mono_assembly_addref (reference);
1424 			if (image->assembly)
1425 				mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1426 				    image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
1427 		} else {
1428 			if (image->assembly)
1429 				mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p].",
1430 				    image->assembly->aname.name, image->assembly);
1431 		}
1432 
1433 		image->references [index] = reference;
1434 	}
1435 	mono_assemblies_unlock ();
1436 
1437 	if (image->references [index] != reference) {
1438 		/* Somebody loaded it before us */
1439 		mono_assembly_close (reference);
1440 	}
1441 }
1442 
1443 /**
1444  * mono_assembly_load_references:
1445  * \param image
1446  * \param status
1447  * \deprecated There is no reason to use this method anymore, it does nothing
1448  *
1449  * This method is now a no-op, it does nothing other than setting the \p status to \c MONO_IMAGE_OK
1450  */
1451 void
mono_assembly_load_references(MonoImage * image,MonoImageOpenStatus * status)1452 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
1453 {
1454 	/* This is a no-op now but it is part of the embedding API so we can't remove it */
1455 	*status = MONO_IMAGE_OK;
1456 }
1457 
1458 typedef struct AssemblyLoadHook AssemblyLoadHook;
1459 struct AssemblyLoadHook {
1460 	AssemblyLoadHook *next;
1461 	MonoAssemblyLoadFunc func;
1462 	gpointer user_data;
1463 };
1464 
1465 AssemblyLoadHook *assembly_load_hook = NULL;
1466 
1467 /**
1468  * mono_assembly_invoke_load_hook:
1469  */
1470 void
mono_assembly_invoke_load_hook(MonoAssembly * ass)1471 mono_assembly_invoke_load_hook (MonoAssembly *ass)
1472 {
1473 	AssemblyLoadHook *hook;
1474 
1475 	for (hook = assembly_load_hook; hook; hook = hook->next) {
1476 		hook->func (ass, hook->user_data);
1477 	}
1478 }
1479 
1480 /**
1481  * mono_install_assembly_load_hook:
1482  */
1483 void
mono_install_assembly_load_hook(MonoAssemblyLoadFunc func,gpointer user_data)1484 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
1485 {
1486 	AssemblyLoadHook *hook;
1487 
1488 	g_return_if_fail (func != NULL);
1489 
1490 	hook = g_new0 (AssemblyLoadHook, 1);
1491 	hook->func = func;
1492 	hook->user_data = user_data;
1493 	hook->next = assembly_load_hook;
1494 	assembly_load_hook = hook;
1495 }
1496 
1497 static void
free_assembly_load_hooks(void)1498 free_assembly_load_hooks (void)
1499 {
1500 	AssemblyLoadHook *hook, *next;
1501 
1502 	for (hook = assembly_load_hook; hook; hook = next) {
1503 		next = hook->next;
1504 		g_free (hook);
1505 	}
1506 }
1507 
1508 typedef struct AssemblySearchHook AssemblySearchHook;
1509 struct AssemblySearchHook {
1510 	AssemblySearchHook *next;
1511 	MonoAssemblySearchFunc func;
1512 	gboolean refonly;
1513 	gboolean postload;
1514 	gpointer user_data;
1515 };
1516 
1517 AssemblySearchHook *assembly_search_hook = NULL;
1518 
1519 static MonoAssembly*
mono_assembly_invoke_search_hook_internal(MonoAssemblyName * aname,MonoAssembly * requesting,gboolean refonly,gboolean postload)1520 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload)
1521 {
1522 	AssemblySearchHook *hook;
1523 
1524 	for (hook = assembly_search_hook; hook; hook = hook->next) {
1525 		if ((hook->refonly == refonly) && (hook->postload == postload)) {
1526 			MonoAssembly *ass;
1527 			/**
1528 			  * A little explanation is in order here.
1529 			  *
1530 			  * The default postload search hook needs to know the requesting assembly to report it to managed code.
1531 			  * The embedding API exposes a search hook that doesn't take such argument.
1532 			  *
1533 			  * The original fix would call the default search hook before all the registered ones and pass
1534 			  * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
1535 			  * rely on. Which is the ordering between user hooks and the default runtime hook.
1536 			  *
1537 			  * Registering the hook after mono_jit_init would let your hook run before the default one and
1538 			  * when using it to handle non standard app layouts this could save your app from a massive amount
1539 			  * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
1540 			  * are all using this trick and if we broke this assumption they would be very disapointed at us.
1541 			  *
1542 			  * So what's the fix? We register the default hook using regular means and special case it when iterating
1543 			  * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
1544 			  * assembly.
1545 			  */
1546 			if (hook->func == (void*)mono_domain_assembly_postload_search)
1547 				ass = mono_domain_assembly_postload_search (aname, requesting, refonly);
1548 			else
1549 				ass = hook->func (aname, hook->user_data);
1550 			if (ass)
1551 				return ass;
1552 		}
1553 	}
1554 
1555 	return NULL;
1556 }
1557 
1558 /**
1559  * mono_assembly_invoke_search_hook:
1560  */
1561 MonoAssembly*
mono_assembly_invoke_search_hook(MonoAssemblyName * aname)1562 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
1563 {
1564 	return mono_assembly_invoke_search_hook_internal (aname, NULL, FALSE, FALSE);
1565 }
1566 
1567 static void
mono_install_assembly_search_hook_internal(MonoAssemblySearchFunc func,gpointer user_data,gboolean refonly,gboolean postload)1568 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func, gpointer user_data, gboolean refonly, gboolean postload)
1569 {
1570 	AssemblySearchHook *hook;
1571 
1572 	g_return_if_fail (func != NULL);
1573 
1574 	hook = g_new0 (AssemblySearchHook, 1);
1575 	hook->func = func;
1576 	hook->user_data = user_data;
1577 	hook->refonly = refonly;
1578 	hook->postload = postload;
1579 	hook->next = assembly_search_hook;
1580 	assembly_search_hook = hook;
1581 }
1582 
1583 /**
1584  * mono_install_assembly_search_hook:
1585  */
1586 void
mono_install_assembly_search_hook(MonoAssemblySearchFunc func,gpointer user_data)1587 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1588 {
1589 	mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
1590 }
1591 
1592 static void
free_assembly_search_hooks(void)1593 free_assembly_search_hooks (void)
1594 {
1595 	AssemblySearchHook *hook, *next;
1596 
1597 	for (hook = assembly_search_hook; hook; hook = next) {
1598 		next = hook->next;
1599 		g_free (hook);
1600 	}
1601 }
1602 
1603 /**
1604  * mono_install_assembly_refonly_search_hook:
1605  */
1606 void
mono_install_assembly_refonly_search_hook(MonoAssemblySearchFunc func,gpointer user_data)1607 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1608 {
1609 	mono_install_assembly_search_hook_internal (func, user_data, TRUE, FALSE);
1610 }
1611 
1612 /**
1613  * mono_install_assembly_postload_search_hook:
1614  */
1615 void
mono_install_assembly_postload_search_hook(MonoAssemblySearchFunc func,gpointer user_data)1616 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1617 {
1618 	mono_install_assembly_search_hook_internal (func, user_data, FALSE, TRUE);
1619 }
1620 
1621 void
mono_install_assembly_postload_refonly_search_hook(MonoAssemblySearchFunc func,gpointer user_data)1622 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1623 {
1624 	mono_install_assembly_search_hook_internal (func, user_data, TRUE, TRUE);
1625 }
1626 
1627 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
1628 struct AssemblyPreLoadHook {
1629 	AssemblyPreLoadHook *next;
1630 	MonoAssemblyPreLoadFunc func;
1631 	gpointer user_data;
1632 };
1633 
1634 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
1635 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
1636 
1637 static MonoAssembly *
invoke_assembly_preload_hook(MonoAssemblyName * aname,gchar ** assemblies_path)1638 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1639 {
1640 	AssemblyPreLoadHook *hook;
1641 	MonoAssembly *assembly;
1642 
1643 	for (hook = assembly_preload_hook; hook; hook = hook->next) {
1644 		assembly = hook->func (aname, assemblies_path, hook->user_data);
1645 		if (assembly != NULL)
1646 			return assembly;
1647 	}
1648 
1649 	return NULL;
1650 }
1651 
1652 static MonoAssembly *
invoke_assembly_refonly_preload_hook(MonoAssemblyName * aname,gchar ** assemblies_path)1653 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1654 {
1655 	AssemblyPreLoadHook *hook;
1656 	MonoAssembly *assembly;
1657 
1658 	for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
1659 		assembly = hook->func (aname, assemblies_path, hook->user_data);
1660 		if (assembly != NULL)
1661 			return assembly;
1662 	}
1663 
1664 	return NULL;
1665 }
1666 
1667 /**
1668  * mono_install_assembly_preload_hook:
1669  */
1670 void
mono_install_assembly_preload_hook(MonoAssemblyPreLoadFunc func,gpointer user_data)1671 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1672 {
1673 	AssemblyPreLoadHook *hook;
1674 
1675 	g_return_if_fail (func != NULL);
1676 
1677 	hook = g_new0 (AssemblyPreLoadHook, 1);
1678 	hook->func = func;
1679 	hook->user_data = user_data;
1680 	hook->next = assembly_preload_hook;
1681 	assembly_preload_hook = hook;
1682 }
1683 
1684 /**
1685  * mono_install_assembly_refonly_preload_hook:
1686  */
1687 void
mono_install_assembly_refonly_preload_hook(MonoAssemblyPreLoadFunc func,gpointer user_data)1688 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1689 {
1690 	AssemblyPreLoadHook *hook;
1691 
1692 	g_return_if_fail (func != NULL);
1693 
1694 	hook = g_new0 (AssemblyPreLoadHook, 1);
1695 	hook->func = func;
1696 	hook->user_data = user_data;
1697 	hook->next = assembly_refonly_preload_hook;
1698 	assembly_refonly_preload_hook = hook;
1699 }
1700 
1701 static void
free_assembly_preload_hooks(void)1702 free_assembly_preload_hooks (void)
1703 {
1704 	AssemblyPreLoadHook *hook, *next;
1705 
1706 	for (hook = assembly_preload_hook; hook; hook = next) {
1707 		next = hook->next;
1708 		g_free (hook);
1709 	}
1710 
1711 	for (hook = assembly_refonly_preload_hook; hook; hook = next) {
1712 		next = hook->next;
1713 		g_free (hook);
1714 	}
1715 }
1716 
1717 static gchar *
absolute_dir(const gchar * filename)1718 absolute_dir (const gchar *filename)
1719 {
1720 	gchar *cwd;
1721 	gchar *mixed;
1722 	gchar **parts;
1723 	gchar *part;
1724 	GList *list, *tmp;
1725 	GString *result;
1726 	gchar *res;
1727 	gint i;
1728 
1729 	if (g_path_is_absolute (filename)) {
1730 		part = g_path_get_dirname (filename);
1731 		res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL);
1732 		g_free (part);
1733 		return res;
1734 	}
1735 
1736 	cwd = g_get_current_dir ();
1737 	mixed = g_build_filename (cwd, filename, NULL);
1738 	parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
1739 	g_free (mixed);
1740 	g_free (cwd);
1741 
1742 	list = NULL;
1743 	for (i = 0; (part = parts [i]) != NULL; i++) {
1744 		if (!strcmp (part, "."))
1745 			continue;
1746 
1747 		if (!strcmp (part, "..")) {
1748 			if (list && list->next) /* Don't remove root */
1749 				list = g_list_delete_link (list, list);
1750 		} else {
1751 			list = g_list_prepend (list, part);
1752 		}
1753 	}
1754 
1755 	result = g_string_new ("");
1756 	list = g_list_reverse (list);
1757 
1758 	/* Ignores last data pointer, which should be the filename */
1759 	for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
1760 		if (tmp->data)
1761 			g_string_append_printf (result, "%s%c", (char *) tmp->data,
1762 								G_DIR_SEPARATOR);
1763 	}
1764 
1765 	res = result->str;
1766 	g_string_free (result, FALSE);
1767 	g_list_free (list);
1768 	g_strfreev (parts);
1769 	if (*res == '\0') {
1770 		g_free (res);
1771 		return g_strdup (".");
1772 	}
1773 
1774 	return res;
1775 }
1776 
1777 /**
1778  * mono_assembly_open_from_bundle:
1779  * \param filename Filename requested
1780  * \param status return status code
1781  *
1782  * This routine tries to open the assembly specified by \p filename from the
1783  * defined bundles, if found, returns the MonoImage for it, if not found
1784  * returns NULL
1785  */
1786 MonoImage *
mono_assembly_open_from_bundle(const char * filename,MonoImageOpenStatus * status,gboolean refonly)1787 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1788 {
1789 	int i;
1790 	char *name;
1791 	gchar *lowercase_filename;
1792 	MonoImage *image = NULL;
1793 	gboolean is_satellite = FALSE;
1794 	/*
1795 	 * we do a very simple search for bundled assemblies: it's not a general
1796 	 * purpose assembly loading mechanism.
1797 	 */
1798 
1799 	if (!bundles)
1800 		return NULL;
1801 
1802 	lowercase_filename = g_utf8_strdown (filename, -1);
1803 	is_satellite = g_str_has_suffix (lowercase_filename, ".resources.dll");
1804 	g_free (lowercase_filename);
1805 	name = g_path_get_basename (filename);
1806 	mono_assemblies_lock ();
1807 	for (i = 0; !image && bundles [i]; ++i) {
1808 		if (strcmp (bundles [i]->name, is_satellite ? filename : name) == 0) {
1809 			image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
1810 			break;
1811 		}
1812 	}
1813 	mono_assemblies_unlock ();
1814 	if (image) {
1815 		mono_image_addref (image);
1816 		mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", is_satellite ? filename : name);
1817 		g_free (name);
1818 		return image;
1819 	}
1820 	g_free (name);
1821 	return NULL;
1822 }
1823 
1824 /**
1825  * mono_assembly_open_full:
1826  * \param filename the file to load
1827  * \param status return status code
1828  * \param refonly Whether this assembly is being opened in "reflection-only" mode.
1829  *
1830  * This loads an assembly from the specified \p filename. The \p filename allows
1831  * a local URL (starting with a \c file:// prefix).  If a file prefix is used, the
1832  * filename is interpreted as a URL, and the filename is URL-decoded.   Otherwise the file
1833  * is treated as a local path.
1834  *
1835  * First, an attempt is made to load the assembly from the bundled executable (for those
1836  * deployments that have been done with the \c mkbundle tool or for scenarios where the
1837  * assembly has been registered as an embedded assembly).   If this is not the case, then
1838  * the assembly is loaded from disk using `api:mono_image_open_full`.
1839  *
1840  * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1841  * the assembly is made.
1842  *
1843  * If \p refonly is set to true, then the assembly is loaded purely for inspection with
1844  * the \c System.Reflection API.
1845  *
1846  * \returns NULL on error, with the \p status set to an error code, or a pointer
1847  * to the assembly.
1848  */
1849 MonoAssembly *
mono_assembly_open_full(const char * filename,MonoImageOpenStatus * status,gboolean refonly)1850 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1851 {
1852 	return mono_assembly_open_a_lot (filename, status, refonly, FALSE);
1853 }
1854 
1855 MonoAssembly *
mono_assembly_open_a_lot(const char * filename,MonoImageOpenStatus * status,gboolean refonly,gboolean load_from_context)1856 mono_assembly_open_a_lot (const char *filename, MonoImageOpenStatus *status, gboolean refonly, gboolean load_from_context)
1857 {
1858 	return mono_assembly_open_predicate (filename, refonly, load_from_context, NULL, NULL, status);
1859 }
1860 
1861 MonoAssembly *
mono_assembly_open_predicate(const char * filename,gboolean refonly,gboolean load_from_context,MonoAssemblyCandidatePredicate predicate,gpointer user_data,MonoImageOpenStatus * status)1862 mono_assembly_open_predicate (const char *filename, gboolean refonly,
1863 			      gboolean load_from_context,
1864 			      MonoAssemblyCandidatePredicate predicate,
1865 			      gpointer user_data,
1866 			      MonoImageOpenStatus *status)
1867 {
1868 	MonoImage *image;
1869 	MonoAssembly *ass;
1870 	MonoImageOpenStatus def_status;
1871 	gchar *fname;
1872 	gchar *new_fname;
1873 	gboolean loaded_from_bundle;
1874 
1875 	g_return_val_if_fail (filename != NULL, NULL);
1876 
1877 	if (!status)
1878 		status = &def_status;
1879 	*status = MONO_IMAGE_OK;
1880 
1881 	if (strncmp (filename, "file://", 7) == 0) {
1882 		GError *error = NULL;
1883 		gchar *uri = (gchar *) filename;
1884 		gchar *tmpuri;
1885 
1886 		/*
1887 		 * MS allows file://c:/... and fails on file://localhost/c:/...
1888 		 * They also throw an IndexOutOfRangeException if "file://"
1889 		 */
1890 		if (uri [7] != '/')
1891 			uri = g_strdup_printf ("file:///%s", uri + 7);
1892 
1893 		tmpuri = uri;
1894 		uri = mono_escape_uri_string (tmpuri);
1895 		fname = g_filename_from_uri (uri, NULL, &error);
1896 		g_free (uri);
1897 
1898 		if (tmpuri != filename)
1899 			g_free (tmpuri);
1900 
1901 		if (error != NULL) {
1902 			g_warning ("%s\n", error->message);
1903 			g_error_free (error);
1904 			fname = g_strdup (filename);
1905 		}
1906 	} else {
1907 		fname = g_strdup (filename);
1908 	}
1909 
1910 	mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1911 			"Assembly Loader probing location: '%s'.", fname);
1912 
1913 	new_fname = NULL;
1914 	if (!mono_assembly_is_in_gac (fname)) {
1915 		MonoError error;
1916 		new_fname = mono_make_shadow_copy (fname, &error);
1917 		if (!is_ok (&error)) {
1918 			mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1919 				    "Assembly Loader shadow copy error: %s.", mono_error_get_message (&error));
1920 			mono_error_cleanup (&error);
1921 			*status = MONO_IMAGE_IMAGE_INVALID;
1922 			g_free (fname);
1923 			return NULL;
1924 		}
1925 	}
1926 	if (new_fname && new_fname != fname) {
1927 		g_free (fname);
1928 		fname = new_fname;
1929 		mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1930 			    "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1931 	}
1932 
1933 	image = NULL;
1934 
1935 	// If VM built with mkbundle
1936 	loaded_from_bundle = FALSE;
1937 	if (bundles != NULL) {
1938 		image = mono_assembly_open_from_bundle (fname, status, refonly);
1939 		loaded_from_bundle = image != NULL;
1940 	}
1941 
1942 	if (!image)
1943 		image = mono_image_open_a_lot (fname, status, refonly, load_from_context);
1944 
1945 	if (!image){
1946 		if (*status == MONO_IMAGE_OK)
1947 			*status = MONO_IMAGE_ERROR_ERRNO;
1948 		g_free (fname);
1949 		return NULL;
1950 	}
1951 
1952 	if (image->assembly) {
1953 		/* We want to return the MonoAssembly that's already loaded,
1954 		 * but if we're using the strict assembly loader, we also need
1955 		 * to check that the previously loaded assembly matches the
1956 		 * predicate.  It could be that we previously loaded a
1957 		 * different version that happens to have the filename that
1958 		 * we're currently probing. */
1959 		if (mono_loader_get_strict_strong_names () &&
1960 		    predicate && !predicate (image->assembly, user_data)) {
1961 			mono_image_close (image);
1962 			g_free (fname);
1963 			return NULL;
1964 		} else {
1965 			/* Already loaded by another appdomain */
1966 			mono_assembly_invoke_load_hook (image->assembly);
1967 			mono_image_close (image);
1968 			g_free (fname);
1969 			return image->assembly;
1970 		}
1971 	}
1972 
1973 	ass = mono_assembly_load_from_predicate (image, fname, refonly, predicate, user_data, status);
1974 
1975 	if (ass) {
1976 		if (!loaded_from_bundle)
1977 			mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1978 				"Assembly Loader loaded assembly from location: '%s'.", filename);
1979 		if (!refonly)
1980 			mono_config_for_assembly (ass->image);
1981 	}
1982 
1983 	/* Clear the reference added by mono_image_open */
1984 	mono_image_close (image);
1985 
1986 	g_free (fname);
1987 
1988 	return ass;
1989 }
1990 
1991 static void
free_item(gpointer val,gpointer user_data)1992 free_item (gpointer val, gpointer user_data)
1993 {
1994 	g_free (val);
1995 }
1996 
1997 /**
1998  * mono_assembly_load_friends:
1999  * \param ass an assembly
2000  *
2001  * Load the list of friend assemblies that are allowed to access
2002  * the assembly's internal types and members. They are stored as assembly
2003  * names in custom attributes.
2004  *
2005  * This is an internal method, we need this because when we load mscorlib
2006  * we do not have the internals visible cattr loaded yet,
2007  * so we need to load these after we initialize the runtime.
2008  *
2009  * LOCKING: Acquires the assemblies lock plus the loader lock.
2010  */
2011 void
mono_assembly_load_friends(MonoAssembly * ass)2012 mono_assembly_load_friends (MonoAssembly* ass)
2013 {
2014 	MonoError error;
2015 	int i;
2016 	MonoCustomAttrInfo* attrs;
2017 	GSList *list;
2018 
2019 	if (ass->friend_assembly_names_inited)
2020 		return;
2021 
2022 	attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
2023 	mono_error_assert_ok (&error);
2024 	if (!attrs) {
2025 		mono_assemblies_lock ();
2026 		ass->friend_assembly_names_inited = TRUE;
2027 		mono_assemblies_unlock ();
2028 		return;
2029 	}
2030 
2031 	mono_assemblies_lock ();
2032 	if (ass->friend_assembly_names_inited) {
2033 		mono_assemblies_unlock ();
2034 		return;
2035 	}
2036 	mono_assemblies_unlock ();
2037 
2038 	list = NULL;
2039 	/*
2040 	 * We build the list outside the assemblies lock, the worse that can happen
2041 	 * is that we'll need to free the allocated list.
2042 	 */
2043 	for (i = 0; i < attrs->num_attrs; ++i) {
2044 		MonoCustomAttrEntry *attr = &attrs->attrs [i];
2045 		MonoAssemblyName *aname;
2046 		const gchar *data;
2047 		uint32_t data_length;
2048 		gchar *data_with_terminator;
2049 		/* Do some sanity checking */
2050 		if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
2051 			continue;
2052 		if (attr->data_size < 4)
2053 			continue;
2054 		data = (const char*)attr->data;
2055 		/* 0xFF means null string, see custom attr format */
2056 		if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
2057 			continue;
2058 		data_length = mono_metadata_decode_value (data + 2, &data);
2059 		data_with_terminator = (char *)g_memdup (data, data_length + 1);
2060 		data_with_terminator[data_length] = 0;
2061 		aname = g_new0 (MonoAssemblyName, 1);
2062 		/*g_print ("friend ass: %s\n", data);*/
2063 		if (mono_assembly_name_parse_full (data_with_terminator, aname, TRUE, NULL, NULL)) {
2064 			list = g_slist_prepend (list, aname);
2065 		} else {
2066 			g_free (aname);
2067 		}
2068 		g_free (data_with_terminator);
2069 	}
2070 	mono_custom_attrs_free (attrs);
2071 
2072 	mono_assemblies_lock ();
2073 	if (ass->friend_assembly_names_inited) {
2074 		mono_assemblies_unlock ();
2075 		g_slist_foreach (list, free_item, NULL);
2076 		g_slist_free (list);
2077 		return;
2078 	}
2079 	ass->friend_assembly_names = list;
2080 
2081 	/* Because of the double checked locking pattern above */
2082 	mono_memory_barrier ();
2083 	ass->friend_assembly_names_inited = TRUE;
2084 	mono_assemblies_unlock ();
2085 }
2086 
2087 struct HasReferenceAssemblyAttributeIterData {
2088 	gboolean has_attr;
2089 };
2090 
2091 static gboolean
has_reference_assembly_attribute_iterator(MonoImage * image,guint32 typeref_scope_token,const char * nspace,const char * name,guint32 method_token,gpointer user_data)2092 has_reference_assembly_attribute_iterator (MonoImage *image, guint32 typeref_scope_token, const char *nspace, const char *name, guint32 method_token, gpointer user_data)
2093 {
2094 	gboolean stop_scanning = FALSE;
2095 	struct HasReferenceAssemblyAttributeIterData *iter_data = (struct HasReferenceAssemblyAttributeIterData*)user_data;
2096 
2097 	if (!strcmp (name, "ReferenceAssemblyAttribute") && !strcmp (nspace, "System.Runtime.CompilerServices")) {
2098 		/* Note we don't check the assembly name, same as coreCLR. */
2099 		iter_data->has_attr = TRUE;
2100 		stop_scanning = TRUE;
2101 	}
2102 
2103 	return stop_scanning;
2104 }
2105 
2106 /**
2107  * mono_assembly_has_reference_assembly_attribute:
2108  * \param assembly a MonoAssembly
2109  * \param error set on error.
2110  *
2111  * \returns TRUE if \p assembly has the \c System.Runtime.CompilerServices.ReferenceAssemblyAttribute set.
2112  * On error returns FALSE and sets \p error.
2113  */
2114 gboolean
mono_assembly_has_reference_assembly_attribute(MonoAssembly * assembly,MonoError * error)2115 mono_assembly_has_reference_assembly_attribute (MonoAssembly *assembly, MonoError *error)
2116 {
2117 	g_assert (assembly && assembly->image);
2118 	/* .NET Framework appears to ignore the attribute on dynamic
2119 	 * assemblies, so don't call this function for dynamic assemblies. */
2120 	g_assert (!image_is_dynamic (assembly->image));
2121 	error_init (error);
2122 
2123 	/*
2124 	 * This might be called during assembly loading, so do everything using the low-level
2125 	 * metadata APIs.
2126 	 */
2127 
2128 	struct HasReferenceAssemblyAttributeIterData iter_data = { FALSE };
2129 
2130 	mono_assembly_metadata_foreach_custom_attr (assembly, &has_reference_assembly_attribute_iterator, &iter_data);
2131 
2132 	return iter_data.has_attr;
2133 }
2134 
2135 /**
2136  * mono_assembly_open:
2137  * \param filename Opens the assembly pointed out by this name
2138  * \param status return status code
2139  *
2140  * This loads an assembly from the specified \p filename. The \p filename allows
2141  * a local URL (starting with a \c file:// prefix).  If a file prefix is used, the
2142  * filename is interpreted as a URL, and the filename is URL-decoded.   Otherwise the file
2143  * is treated as a local path.
2144  *
2145  * First, an attempt is made to load the assembly from the bundled executable (for those
2146  * deployments that have been done with the \c mkbundle tool or for scenarios where the
2147  * assembly has been registered as an embedded assembly).   If this is not the case, then
2148  * the assembly is loaded from disk using `api:mono_image_open_full`.
2149  *
2150  * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
2151  * the assembly is made.
2152  *
2153  * \returns a pointer to the \c MonoAssembly if \p filename contains a valid
2154  * assembly or NULL on error.  Details about the error are stored in the
2155  * \p status variable.
2156  */
2157 MonoAssembly *
mono_assembly_open(const char * filename,MonoImageOpenStatus * status)2158 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
2159 {
2160 	return mono_assembly_open_predicate (filename, FALSE, FALSE, NULL, NULL, status);
2161 }
2162 
2163 /**
2164  * mono_assembly_load_from_full:
2165  * \param image Image to load the assembly from
2166  * \param fname assembly name to associate with the assembly
2167  * \param status returns the status condition
2168  * \param refonly Whether this assembly is being opened in "reflection-only" mode.
2169  *
2170  * If the provided \p image has an assembly reference, it will process the given
2171  * image as an assembly with the given name.
2172  *
2173  * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2174  *
2175  * Returns: A valid pointer to a \c MonoAssembly* on success and the \p status will be
2176  * set to \c MONO_IMAGE_OK;  or NULL on error.
2177  *
2178  * If there is an error loading the assembly the \p status will indicate the
2179  * reason with \p status being set to \c MONO_IMAGE_INVALID if the
2180  * image did not contain an assembly reference table.
2181  */
2182 MonoAssembly *
mono_assembly_load_from_full(MonoImage * image,const char * fname,MonoImageOpenStatus * status,gboolean refonly)2183 mono_assembly_load_from_full (MonoImage *image, const char*fname,
2184 			      MonoImageOpenStatus *status, gboolean refonly)
2185 {
2186 	return mono_assembly_load_from_predicate (image, fname, refonly, NULL, NULL, status);
2187 }
2188 
2189 MonoAssembly *
mono_assembly_load_from_predicate(MonoImage * image,const char * fname,gboolean refonly,MonoAssemblyCandidatePredicate predicate,gpointer user_data,MonoImageOpenStatus * status)2190 mono_assembly_load_from_predicate (MonoImage *image, const char *fname,
2191 				   gboolean refonly,
2192 				   MonoAssemblyCandidatePredicate predicate,
2193 				   gpointer user_data,
2194 				   MonoImageOpenStatus *status)
2195 {
2196 	MonoAssembly *ass, *ass2;
2197 	char *base_dir;
2198 
2199 	if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
2200 		/* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
2201 		*status = MONO_IMAGE_IMAGE_INVALID;
2202 		return NULL;
2203 	}
2204 
2205 #if defined (HOST_WIN32)
2206 	{
2207 		gchar *tmp_fn;
2208 		int i;
2209 
2210 		tmp_fn = g_strdup (fname);
2211 		for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
2212 			if (tmp_fn [i] == '/')
2213 				tmp_fn [i] = '\\';
2214 		}
2215 
2216 		base_dir = absolute_dir (tmp_fn);
2217 		g_free (tmp_fn);
2218 	}
2219 #else
2220 	base_dir = absolute_dir (fname);
2221 #endif
2222 
2223 	/*
2224 	 * Create assembly struct, and enter it into the assembly cache
2225 	 */
2226 	ass = g_new0 (MonoAssembly, 1);
2227 	ass->basedir = base_dir;
2228 	ass->ref_only = refonly;
2229 	ass->image = image;
2230 
2231 	MONO_PROFILER_RAISE (assembly_loading, (ass));
2232 
2233 	mono_assembly_fill_assembly_name (image, &ass->aname);
2234 
2235 	if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
2236 		// MS.NET doesn't support loading other mscorlibs
2237 		g_free (ass);
2238 		g_free (base_dir);
2239 		mono_image_addref (mono_defaults.corlib);
2240 		*status = MONO_IMAGE_OK;
2241 		return mono_defaults.corlib->assembly;
2242 	}
2243 
2244 	/* Add a non-temporary reference because of ass->image */
2245 	mono_image_addref (image);
2246 
2247 	mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image addref %s[%p] -> %s[%p]: %d", ass->aname.name, ass, image->name, image, image->ref_count);
2248 
2249 	/*
2250 	 * The load hooks might take locks so we can't call them while holding the
2251 	 * assemblies lock.
2252 	 */
2253 	if (ass->aname.name) {
2254 		ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
2255 		if (ass2) {
2256 			g_free (ass);
2257 			g_free (base_dir);
2258 			mono_image_close (image);
2259 			*status = MONO_IMAGE_OK;
2260 			return ass2;
2261 		}
2262 	}
2263 
2264 	/* We need to check for ReferenceAssmeblyAttribute before we
2265 	 * mark the assembly as loaded and before we fire the load
2266 	 * hook. Otherwise mono_domain_fire_assembly_load () in
2267 	 * appdomain.c will cache a mapping from the assembly name to
2268 	 * this image and we won't be able to look for a different
2269 	 * candidate. */
2270 
2271 	if (!refonly) {
2272 		MonoError refasm_error;
2273 		if (mono_assembly_has_reference_assembly_attribute (ass, &refasm_error)) {
2274 			mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image for assembly '%s' (%s) has ReferenceAssemblyAttribute, skipping", ass->aname.name, image->name);
2275 			g_free (ass);
2276 			g_free (base_dir);
2277 			mono_image_close (image);
2278 			*status = MONO_IMAGE_IMAGE_INVALID;
2279 			return NULL;
2280 		}
2281 		mono_error_cleanup (&refasm_error);
2282 	}
2283 
2284 	if (predicate && !predicate (ass, user_data)) {
2285 		mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate returned FALSE, skipping '%s' (%s)\n", ass->aname.name, image->name);
2286 		g_free (ass);
2287 		g_free (base_dir);
2288 		mono_image_close (image);
2289 		*status = MONO_IMAGE_IMAGE_INVALID;
2290 		return NULL;
2291 	}
2292 
2293 	mono_assemblies_lock ();
2294 
2295 	if (image->assembly) {
2296 		/*
2297 		 * This means another thread has already loaded the assembly, but not yet
2298 		 * called the load hooks so the search hook can't find the assembly.
2299 		 */
2300 		mono_assemblies_unlock ();
2301 		ass2 = image->assembly;
2302 		g_free (ass);
2303 		g_free (base_dir);
2304 		mono_image_close (image);
2305 		*status = MONO_IMAGE_OK;
2306 		return ass2;
2307 	}
2308 
2309 	mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Prepared to set up assembly '%s' (%s)", ass->aname.name, image->name);
2310 
2311 	image->assembly = ass;
2312 
2313 	loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
2314 	mono_assemblies_unlock ();
2315 
2316 #ifdef HOST_WIN32
2317 	if (image->is_module_handle)
2318 		mono_image_fixup_vtable (image);
2319 #endif
2320 
2321 	mono_assembly_invoke_load_hook (ass);
2322 
2323 	MONO_PROFILER_RAISE (assembly_loaded, (ass));
2324 
2325 	return ass;
2326 }
2327 
2328 /**
2329  * mono_assembly_load_from:
2330  * \param image Image to load the assembly from
2331  * \param fname assembly name to associate with the assembly
2332  * \param status return status code
2333  *
2334  * If the provided \p image has an assembly reference, it will process the given
2335  * image as an assembly with the given name.
2336  *
2337  * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2338  *
2339  * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2340  * \p refonly parameter set to FALSE.
2341  * \returns A valid pointer to a \c MonoAssembly* on success and then \p status will be
2342  * set to \c MONO_IMAGE_OK; or NULL on error.
2343  *
2344  * If there is an error loading the assembly the \p status will indicate the
2345  * reason with \p status being set to \c MONO_IMAGE_INVALID if the
2346  * image did not contain an assembly reference table.
2347 
2348  */
2349 MonoAssembly *
mono_assembly_load_from(MonoImage * image,const char * fname,MonoImageOpenStatus * status)2350 mono_assembly_load_from (MonoImage *image, const char *fname,
2351 			 MonoImageOpenStatus *status)
2352 {
2353 	return mono_assembly_load_from_full (image, fname, status, FALSE);
2354 }
2355 
2356 /**
2357  * mono_assembly_name_free:
2358  * \param aname assembly name to free
2359  *
2360  * Frees the provided assembly name object.
2361  * (it does not frees the object itself, only the name members).
2362  */
2363 void
mono_assembly_name_free(MonoAssemblyName * aname)2364 mono_assembly_name_free (MonoAssemblyName *aname)
2365 {
2366 	if (aname == NULL)
2367 		return;
2368 
2369 	g_free ((void *) aname->name);
2370 	g_free ((void *) aname->culture);
2371 	g_free ((void *) aname->hash_value);
2372 	g_free ((guint8*) aname->public_key);
2373 }
2374 
2375 static gboolean
parse_public_key(const gchar * key,gchar ** pubkey,gboolean * is_ecma)2376 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2377 {
2378 	const gchar *pkey;
2379 	gchar header [16], val, *arr, *endp;
2380 	gint i, j, offset, bitlen, keylen, pkeylen;
2381 
2382 	//both pubkey and is_ecma are required arguments
2383 	g_assert (pubkey && is_ecma);
2384 
2385 	keylen = strlen (key) >> 1;
2386 	if (keylen < 1)
2387 		return FALSE;
2388 
2389 	/* allow the ECMA standard key */
2390 	if (strcmp (key, "00000000000000000400000000000000") == 0) {
2391 		*pubkey = NULL;
2392 		*is_ecma = TRUE;
2393 		return TRUE;
2394 	}
2395 	*is_ecma = FALSE;
2396 	val = g_ascii_xdigit_value (key [0]) << 4;
2397 	val |= g_ascii_xdigit_value (key [1]);
2398 	switch (val) {
2399 		case 0x00:
2400 			if (keylen < 13)
2401 				return FALSE;
2402 			val = g_ascii_xdigit_value (key [24]);
2403 			val |= g_ascii_xdigit_value (key [25]);
2404 			if (val != 0x06)
2405 				return FALSE;
2406 			pkey = key + 24;
2407 			break;
2408 		case 0x06:
2409 			pkey = key;
2410 			break;
2411 		default:
2412 			return FALSE;
2413 	}
2414 
2415 	/* We need the first 16 bytes
2416 	* to check whether this key is valid or not */
2417 	pkeylen = strlen (pkey) >> 1;
2418 	if (pkeylen < 16)
2419 		return FALSE;
2420 
2421 	for (i = 0, j = 0; i < 16; i++) {
2422 		header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2423 		header [i] |= g_ascii_xdigit_value (pkey [j++]);
2424 	}
2425 
2426 	if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2427 			header [1] != 0x02 || /* Version (0x02) */
2428 			header [2] != 0x00 || /* Reserved (word) */
2429 			header [3] != 0x00 ||
2430 			(guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2431 		return FALSE;
2432 
2433 	/* Based on this length, we _should_ be able to know if the length is right */
2434 	bitlen = read32 (header + 12) >> 3;
2435 	if ((bitlen + 16 + 4) != pkeylen)
2436 		return FALSE;
2437 
2438 	arr = (gchar *)g_malloc (keylen + 4);
2439 	/* Encode the size of the blob */
2440 	mono_metadata_encode_value (keylen, &arr[0], &endp);
2441 	offset = (gint)(endp-arr);
2442 
2443 	for (i = offset, j = 0; i < keylen + offset; i++) {
2444 		arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2445 		arr [i] |= g_ascii_xdigit_value (key [j++]);
2446 	}
2447 
2448 	*pubkey = arr;
2449 
2450 	return TRUE;
2451 }
2452 
2453 static gboolean
build_assembly_name(const char * name,const char * version,const char * culture,const char * token,const char * key,guint32 flags,guint32 arch,MonoAssemblyName * aname,gboolean save_public_key)2454 build_assembly_name (const char *name, const char *version, const char *culture, const char *token, const char *key, guint32 flags, guint32 arch, MonoAssemblyName *aname, gboolean save_public_key)
2455 {
2456 	gint major, minor, build, revision;
2457 	gint len;
2458 	gint version_parts;
2459 	gchar *pkeyptr, *encoded, tok [8];
2460 
2461 	memset (aname, 0, sizeof (MonoAssemblyName));
2462 
2463 	if (version) {
2464 		version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2465 		if (version_parts < 2 || version_parts > 4)
2466 			return FALSE;
2467 
2468 		/* FIXME: we should set build & revision to -1 (instead of 0)
2469 		if these are not set in the version string. That way, later on,
2470 		we can still determine if these were specified.	*/
2471 		aname->major = major;
2472 		aname->minor = minor;
2473 		if (version_parts >= 3)
2474 			aname->build = build;
2475 		else
2476 			aname->build = 0;
2477 		if (version_parts == 4)
2478 			aname->revision = revision;
2479 		else
2480 			aname->revision = 0;
2481 	}
2482 
2483 	aname->flags = flags;
2484 	aname->arch = arch;
2485 	aname->name = g_strdup (name);
2486 
2487 	if (culture) {
2488 		if (g_ascii_strcasecmp (culture, "neutral") == 0)
2489 			aname->culture = g_strdup ("");
2490 		else
2491 			aname->culture = g_strdup (culture);
2492 	}
2493 
2494 	if (token && strncmp (token, "null", 4) != 0) {
2495 		char *lower;
2496 
2497 		/* the constant includes the ending NULL, hence the -1 */
2498 		if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2499 			mono_assembly_name_free (aname);
2500 			return FALSE;
2501 		}
2502 		lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2503 		g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2504 		g_free (lower);
2505 	}
2506 
2507 	if (key) {
2508 		gboolean is_ecma = FALSE;
2509 		gchar *pkey = NULL;
2510 		if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2511 			mono_assembly_name_free (aname);
2512 			return FALSE;
2513 		}
2514 
2515 		if (is_ecma) {
2516 			g_assert (pkey == NULL);
2517 			aname->public_key = NULL;
2518 			g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2519 			return TRUE;
2520 		}
2521 
2522 		len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2523 		// We also need to generate the key token
2524 		mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2525 		encoded = encode_public_tok ((guchar*) tok, 8);
2526 		g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2527 		g_free (encoded);
2528 
2529 		if (save_public_key)
2530 			aname->public_key = (guint8*) pkey;
2531 		else
2532 			g_free (pkey);
2533 	}
2534 
2535 	return TRUE;
2536 }
2537 
2538 static gboolean
parse_assembly_directory_name(const char * name,const char * dirname,MonoAssemblyName * aname)2539 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2540 {
2541 	gchar **parts;
2542 	gboolean res;
2543 
2544 	parts = g_strsplit (dirname, "_", 3);
2545 	if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2546 		g_strfreev (parts);
2547 		return FALSE;
2548 	}
2549 
2550 	res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2551 	g_strfreev (parts);
2552 	return res;
2553 }
2554 
2555 static gboolean
split_key_value(const gchar * pair,gchar ** key,guint32 * keylen,gchar ** value)2556 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2557 {
2558 	char *eqsign = strchr (pair, '=');
2559 	if (!eqsign) {
2560 		*key = NULL;
2561 		*keylen = 0;
2562 		*value = NULL;
2563 		return FALSE;
2564 	}
2565 
2566 	*key = (gchar*)pair;
2567 	*keylen = eqsign - *key;
2568 	while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2569 		(*keylen)--;
2570 	*value = g_strstrip (eqsign + 1);
2571 	return TRUE;
2572 }
2573 
2574 gboolean
mono_assembly_name_parse_full(const char * name,MonoAssemblyName * aname,gboolean save_public_key,gboolean * is_version_defined,gboolean * is_token_defined)2575 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2576 {
2577 	gchar *dllname;
2578 	gchar *dllname_uq;
2579 	gchar *version = NULL;
2580 	gchar *version_uq;
2581 	gchar *culture = NULL;
2582 	gchar *culture_uq;
2583 	gchar *token = NULL;
2584 	gchar *token_uq;
2585 	gchar *key = NULL;
2586 	gchar *key_uq;
2587 	gchar *retargetable = NULL;
2588 	gchar *retargetable_uq;
2589 	gchar *procarch;
2590 	gchar *procarch_uq;
2591 	gboolean res;
2592 	gchar *value, *part_name;
2593 	guint32 part_name_len;
2594 	gchar **parts;
2595 	gchar **tmp;
2596 	gboolean version_defined;
2597 	gboolean token_defined;
2598 	guint32 flags = 0;
2599 	guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2600 
2601 	if (!is_version_defined)
2602 		is_version_defined = &version_defined;
2603 	*is_version_defined = FALSE;
2604 	if (!is_token_defined)
2605 		is_token_defined = &token_defined;
2606 	*is_token_defined = FALSE;
2607 
2608 	parts = tmp = g_strsplit (name, ",", 6);
2609 	if (!tmp || !*tmp) {
2610 		g_strfreev (tmp);
2611 		return FALSE;
2612 	}
2613 
2614 	dllname = g_strstrip (*tmp);
2615 
2616 	tmp++;
2617 
2618 	while (*tmp) {
2619 		if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2620 			goto cleanup_and_fail;
2621 
2622 		if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2623 			*is_version_defined = TRUE;
2624 			version = value;
2625 			if (strlen (version) == 0) {
2626 				goto cleanup_and_fail;
2627 			}
2628 			tmp++;
2629 			continue;
2630 		}
2631 
2632 		if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2633 			culture = value;
2634 			if (strlen (culture) == 0) {
2635 				goto cleanup_and_fail;
2636 			}
2637 			tmp++;
2638 			continue;
2639 		}
2640 
2641 		if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2642 			*is_token_defined = TRUE;
2643 			token = value;
2644 			if (strlen (token) == 0) {
2645 				goto cleanup_and_fail;
2646 			}
2647 			tmp++;
2648 			continue;
2649 		}
2650 
2651 		if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2652 			key = value;
2653 			if (strlen (key) == 0) {
2654 				goto cleanup_and_fail;
2655 			}
2656 			tmp++;
2657 			continue;
2658 		}
2659 
2660 		if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2661 			retargetable = value;
2662 			retargetable_uq = unquote (retargetable);
2663 			if (retargetable_uq != NULL)
2664 				retargetable = retargetable_uq;
2665 
2666 			if (!g_ascii_strcasecmp (retargetable, "yes")) {
2667 				flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2668 			} else if (g_ascii_strcasecmp (retargetable, "no")) {
2669 				g_free (retargetable_uq);
2670 				goto cleanup_and_fail;
2671 			}
2672 
2673 			g_free (retargetable_uq);
2674 			tmp++;
2675 			continue;
2676 		}
2677 
2678 		if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2679 			procarch = value;
2680 			procarch_uq = unquote (procarch);
2681 			if (procarch_uq != NULL)
2682 				procarch = procarch_uq;
2683 
2684 			if (!g_ascii_strcasecmp (procarch, "MSIL"))
2685 				arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2686 			else if (!g_ascii_strcasecmp (procarch, "X86"))
2687 				arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2688 			else if (!g_ascii_strcasecmp (procarch, "IA64"))
2689 				arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2690 			else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2691 				arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2692 			else {
2693 				g_free (procarch_uq);
2694 				goto cleanup_and_fail;
2695 			}
2696 
2697 			g_free (procarch_uq);
2698 			tmp++;
2699 			continue;
2700 		}
2701 
2702 		g_strfreev (parts);
2703 		return FALSE;
2704 	}
2705 
2706 	/* if retargetable flag is set, then we must have a fully qualified name */
2707 	if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2708 		goto cleanup_and_fail;
2709 	}
2710 
2711 	dllname_uq = unquote (dllname);
2712 	version_uq = unquote (version);
2713 	culture_uq = unquote (culture);
2714 	token_uq = unquote (token);
2715 	key_uq = unquote (key);
2716 
2717 	res = build_assembly_name (
2718 		dllname_uq == NULL ? dllname : dllname_uq,
2719 		version_uq == NULL ? version : version_uq,
2720 		culture_uq == NULL ? culture : culture_uq,
2721 		token_uq == NULL ? token : token_uq,
2722 		key_uq == NULL ? key : key_uq,
2723 		flags, arch, aname, save_public_key);
2724 
2725 	g_free (dllname_uq);
2726 	g_free (version_uq);
2727 	g_free (culture_uq);
2728 	g_free (token_uq);
2729 	g_free (key_uq);
2730 
2731 	g_strfreev (parts);
2732 	return res;
2733 
2734 cleanup_and_fail:
2735 	g_strfreev (parts);
2736 	return FALSE;
2737 }
2738 
2739 static char*
unquote(const char * str)2740 unquote (const char *str)
2741 {
2742 	gint slen;
2743 	const char *end;
2744 
2745 	if (str == NULL)
2746 		return NULL;
2747 
2748 	slen = strlen (str);
2749 	if (slen < 2)
2750 		return NULL;
2751 
2752 	if (*str != '\'' && *str != '\"')
2753 		return NULL;
2754 
2755 	end = str + slen - 1;
2756 	if (*str != *end)
2757 		return NULL;
2758 
2759 	return g_strndup (str + 1, slen - 2);
2760 }
2761 
2762 /**
2763  * mono_assembly_name_parse:
2764  * \param name name to parse
2765  * \param aname the destination assembly name
2766  *
2767  * Parses an assembly qualified type name and assigns the name,
2768  * version, culture and token to the provided assembly name object.
2769  *
2770  * \returns TRUE if the name could be parsed.
2771  */
2772 gboolean
mono_assembly_name_parse(const char * name,MonoAssemblyName * aname)2773 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2774 {
2775 	return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2776 }
2777 
2778 /**
2779  * mono_assembly_name_new:
2780  * \param name name to parse
2781  *
2782  * Allocate a new \c MonoAssemblyName and fill its values from the
2783  * passed \p name.
2784  *
2785  * \returns a newly allocated structure or NULL if there was any failure.
2786  */
2787 MonoAssemblyName*
mono_assembly_name_new(const char * name)2788 mono_assembly_name_new (const char *name)
2789 {
2790 	MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2791 	if (mono_assembly_name_parse (name, aname))
2792 		return aname;
2793 	g_free (aname);
2794 	return NULL;
2795 }
2796 
2797 /**
2798  * mono_assembly_name_get_name:
2799  */
2800 const char*
mono_assembly_name_get_name(MonoAssemblyName * aname)2801 mono_assembly_name_get_name (MonoAssemblyName *aname)
2802 {
2803 	return aname->name;
2804 }
2805 
2806 /**
2807  * mono_assembly_name_get_culture:
2808  */
2809 const char*
mono_assembly_name_get_culture(MonoAssemblyName * aname)2810 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2811 {
2812 	return aname->culture;
2813 }
2814 
2815 /**
2816  * mono_assembly_name_get_pubkeytoken:
2817  */
2818 mono_byte*
mono_assembly_name_get_pubkeytoken(MonoAssemblyName * aname)2819 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2820 {
2821 	if (aname->public_key_token [0])
2822 		return aname->public_key_token;
2823 	return NULL;
2824 }
2825 
2826 /**
2827  * mono_assembly_name_get_version:
2828  */
2829 uint16_t
mono_assembly_name_get_version(MonoAssemblyName * aname,uint16_t * minor,uint16_t * build,uint16_t * revision)2830 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2831 {
2832 	if (minor)
2833 		*minor = aname->minor;
2834 	if (build)
2835 		*build = aname->build;
2836 	if (revision)
2837 		*revision = aname->revision;
2838 	return aname->major;
2839 }
2840 
2841 static MonoAssembly*
probe_for_partial_name(const char * basepath,const char * fullname,MonoAssemblyName * aname,MonoImageOpenStatus * status)2842 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2843 {
2844 	gchar *fullpath = NULL;
2845 	GDir *dirhandle;
2846 	const char* direntry;
2847 	MonoAssemblyName gac_aname;
2848 	gint major=-1, minor=0, build=0, revision=0;
2849 	gboolean exact_version;
2850 
2851 	dirhandle = g_dir_open (basepath, 0, NULL);
2852 	if (!dirhandle)
2853 		return NULL;
2854 
2855 	exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2856 
2857 	while ((direntry = g_dir_read_name (dirhandle))) {
2858 		gboolean match = TRUE;
2859 
2860 		if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2861 			continue;
2862 
2863 		if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2864 			match = FALSE;
2865 
2866 		if (match && strlen ((char*)aname->public_key_token) > 0 &&
2867 				!mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2868 			match = FALSE;
2869 
2870 		if (match) {
2871 			if (exact_version) {
2872 				match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2873 						 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2874 			}
2875 			else if (gac_aname.major < major)
2876 				match = FALSE;
2877 			else if (gac_aname.major == major) {
2878 				if (gac_aname.minor < minor)
2879 					match = FALSE;
2880 				else if (gac_aname.minor == minor) {
2881 					if (gac_aname.build < build)
2882 						match = FALSE;
2883 					else if (gac_aname.build == build && gac_aname.revision <= revision)
2884 						match = FALSE;
2885 				}
2886 			}
2887 		}
2888 
2889 		if (match) {
2890 			major = gac_aname.major;
2891 			minor = gac_aname.minor;
2892 			build = gac_aname.build;
2893 			revision = gac_aname.revision;
2894 			g_free (fullpath);
2895 			fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2896 		}
2897 
2898 		mono_assembly_name_free (&gac_aname);
2899 	}
2900 
2901 	g_dir_close (dirhandle);
2902 
2903 	if (fullpath == NULL)
2904 		return NULL;
2905 	else {
2906 		MonoAssembly *res = mono_assembly_open_predicate (fullpath, FALSE, FALSE, NULL, NULL, status);
2907 		g_free (fullpath);
2908 		return res;
2909 	}
2910 }
2911 
2912 /**
2913  * mono_assembly_load_with_partial_name:
2914  * \param name an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2915  * \param status return status code
2916  *
2917  * Loads a \c MonoAssembly from a name.  The name is parsed using `api:mono_assembly_name_parse`,
2918  * so it might contain a qualified type name, version, culture and token.
2919  *
2920  * This will load the assembly from the file whose name is derived from the assembly name
2921  * by appending the \c .dll extension.
2922  *
2923  * The assembly is loaded from either one of the extra Global Assembly Caches specified
2924  * by the extra GAC paths (specified by the \c MONO_GAC_PREFIX environment variable) or
2925  * if that fails from the GAC.
2926  *
2927  * \returns NULL on failure, or a pointer to a \c MonoAssembly on success.
2928  */
2929 MonoAssembly*
mono_assembly_load_with_partial_name(const char * name,MonoImageOpenStatus * status)2930 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2931 {
2932 	MonoError error;
2933 	MonoAssembly *res;
2934 	MonoAssemblyName *aname, base_name;
2935 	MonoAssemblyName mapped_aname;
2936 	gchar *fullname, *gacpath;
2937 	gchar **paths;
2938 
2939 	memset (&base_name, 0, sizeof (MonoAssemblyName));
2940 	aname = &base_name;
2941 
2942 	if (!mono_assembly_name_parse (name, aname))
2943 		return NULL;
2944 
2945 	/*
2946 	 * If no specific version has been requested, make sure we load the
2947 	 * correct version for system assemblies.
2948 	 */
2949 	if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2950 		aname = mono_assembly_remap_version (aname, &mapped_aname);
2951 
2952 	res = mono_assembly_loaded (aname);
2953 	if (res) {
2954 		mono_assembly_name_free (aname);
2955 		return res;
2956 	}
2957 
2958 	res = invoke_assembly_preload_hook (aname, assemblies_path);
2959 	if (res) {
2960 		res->in_gac = FALSE;
2961 		mono_assembly_name_free (aname);
2962 		return res;
2963 	}
2964 
2965 	fullname = g_strdup_printf ("%s.dll", aname->name);
2966 
2967 	if (extra_gac_paths) {
2968 		paths = extra_gac_paths;
2969 		while (!res && *paths) {
2970 			gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2971 			res = probe_for_partial_name (gacpath, fullname, aname, status);
2972 			g_free (gacpath);
2973 			paths++;
2974 		}
2975 	}
2976 
2977 	if (res) {
2978 		res->in_gac = TRUE;
2979 		g_free (fullname);
2980 		mono_assembly_name_free (aname);
2981 		return res;
2982 	}
2983 
2984 	gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2985 	res = probe_for_partial_name (gacpath, fullname, aname, status);
2986 	g_free (gacpath);
2987 
2988 	g_free (fullname);
2989 	mono_assembly_name_free (aname);
2990 
2991 	if (res)
2992 		res->in_gac = TRUE;
2993 	else {
2994 		MonoDomain *domain = mono_domain_get ();
2995 
2996 		res = mono_try_assembly_resolve (domain, name, NULL, FALSE, &error);
2997 		if (!is_ok (&error)) {
2998 			mono_error_cleanup (&error);
2999 			if (*status == MONO_IMAGE_OK)
3000 				*status = MONO_IMAGE_IMAGE_INVALID;
3001 		}
3002 	}
3003 
3004 	return res;
3005 }
3006 
3007 static MonoBoolean
mono_assembly_is_in_gac(const gchar * filename)3008 mono_assembly_is_in_gac (const gchar *filename)
3009 {
3010 	const gchar *rootdir;
3011 	gchar *gp;
3012 	gchar **paths;
3013 
3014 	if (filename == NULL)
3015 		return FALSE;
3016 
3017 	for (paths = extra_gac_paths; paths && *paths; paths++) {
3018 		if (strstr (*paths, filename) != *paths)
3019 			continue;
3020 
3021 		gp = (gchar *) (filename + strlen (*paths));
3022 		if (*gp != G_DIR_SEPARATOR)
3023 			continue;
3024 		gp++;
3025 		if (strncmp (gp, "lib", 3))
3026 			continue;
3027 		gp += 3;
3028 		if (*gp != G_DIR_SEPARATOR)
3029 			continue;
3030 		gp++;
3031 		if (strncmp (gp, "mono", 4))
3032 			continue;
3033 		gp += 4;
3034 		if (*gp != G_DIR_SEPARATOR)
3035 			continue;
3036 		gp++;
3037 		if (strncmp (gp, "gac", 3))
3038 			continue;
3039 		gp += 3;
3040 		if (*gp != G_DIR_SEPARATOR)
3041 			continue;
3042 
3043 		return TRUE;
3044 	}
3045 
3046 	rootdir = mono_assembly_getrootdir ();
3047 	if (strstr (filename, rootdir) != filename)
3048 		return FALSE;
3049 
3050 	gp = (gchar *) (filename + strlen (rootdir));
3051 	if (*gp != G_DIR_SEPARATOR)
3052 		return FALSE;
3053 	gp++;
3054 	if (strncmp (gp, "mono", 4))
3055 		return FALSE;
3056 	gp += 4;
3057 	if (*gp != G_DIR_SEPARATOR)
3058 		return FALSE;
3059 	gp++;
3060 	if (strncmp (gp, "gac", 3))
3061 		return FALSE;
3062 	gp += 3;
3063 	if (*gp != G_DIR_SEPARATOR)
3064 		return FALSE;
3065 	return TRUE;
3066 }
3067 
3068 static MonoImage*
mono_assembly_load_publisher_policy(MonoAssemblyName * aname)3069 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
3070 {
3071 	MonoImage *image;
3072 	gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
3073 	gchar **paths;
3074 	gint32 len;
3075 
3076 	if (strstr (aname->name, ".dll")) {
3077 		len = strlen (aname->name) - 4;
3078 		name = (gchar *)g_malloc (len + 1);
3079 		memcpy (name, aname->name, len);
3080 		name[len] = 0;
3081 	} else
3082 		name = g_strdup (aname->name);
3083 
3084 	if (aname->culture)
3085 		culture = g_utf8_strdown (aname->culture, -1);
3086 	else
3087 		culture = g_strdup ("");
3088 
3089 	pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
3090 	version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
3091 	g_free (name);
3092 	g_free (culture);
3093 
3094 	filename = g_strconcat (pname, ".dll", NULL);
3095 	subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
3096 	g_free (pname);
3097 	g_free (version);
3098 	g_free (filename);
3099 
3100 	image = NULL;
3101 	if (extra_gac_paths) {
3102 		paths = extra_gac_paths;
3103 		while (!image && *paths) {
3104 			fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
3105 					"lib", "mono", "gac", subpath, NULL);
3106 			image = mono_image_open (fullpath, NULL);
3107 			g_free (fullpath);
3108 			paths++;
3109 		}
3110 	}
3111 
3112 	if (image) {
3113 		g_free (subpath);
3114 		return image;
3115 	}
3116 
3117 	fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3118 			"mono", "gac", subpath, NULL);
3119 	image = mono_image_open (fullpath, NULL);
3120 	g_free (subpath);
3121 	g_free (fullpath);
3122 
3123 	return image;
3124 }
3125 
3126 static MonoAssemblyName*
mono_assembly_bind_version(MonoAssemblyBindingInfo * info,MonoAssemblyName * aname,MonoAssemblyName * dest_name)3127 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3128 {
3129 	memcpy (dest_name, aname, sizeof (MonoAssemblyName));
3130 	dest_name->major = info->new_version.major;
3131 	dest_name->minor = info->new_version.minor;
3132 	dest_name->build = info->new_version.build;
3133 	dest_name->revision = info->new_version.revision;
3134 
3135 	return dest_name;
3136 }
3137 
3138 /* LOCKING: assembly_binding lock must be held */
3139 static MonoAssemblyBindingInfo*
search_binding_loaded(MonoAssemblyName * aname)3140 search_binding_loaded (MonoAssemblyName *aname)
3141 {
3142 	GSList *tmp;
3143 
3144 	for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
3145 		MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
3146 		if (assembly_binding_maps_name (info, aname))
3147 			return info;
3148 	}
3149 
3150 	return NULL;
3151 }
3152 
3153 static inline gboolean
info_compare_versions(AssemblyVersionSet * left,AssemblyVersionSet * right)3154 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
3155 {
3156 	if (left->major != right->major || left->minor != right->minor ||
3157 	    left->build != right->build || left->revision != right->revision)
3158 		return FALSE;
3159 
3160 	return TRUE;
3161 }
3162 
3163 static inline gboolean
info_versions_equal(MonoAssemblyBindingInfo * left,MonoAssemblyBindingInfo * right)3164 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
3165 {
3166 	if (left->has_old_version_bottom != right->has_old_version_bottom)
3167 		return FALSE;
3168 
3169 	if (left->has_old_version_top != right->has_old_version_top)
3170 		return FALSE;
3171 
3172 	if (left->has_new_version != right->has_new_version)
3173 		return FALSE;
3174 
3175 	if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
3176 		return FALSE;
3177 
3178 	if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
3179 		return FALSE;
3180 
3181 	if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
3182 		return FALSE;
3183 
3184 	return TRUE;
3185 }
3186 
3187 /* LOCKING: assumes all the necessary locks are held */
3188 static void
assembly_binding_info_parsed(MonoAssemblyBindingInfo * info,void * user_data)3189 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
3190 {
3191 	MonoAssemblyBindingInfo *info_copy;
3192 	GSList *tmp;
3193 	MonoAssemblyBindingInfo *info_tmp;
3194 	MonoDomain *domain = (MonoDomain*)user_data;
3195 
3196 	if (!domain)
3197 		return;
3198 
3199 	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)) {
3200 		mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Discarding assembly binding to problematic version %s v%d.%d.%d.%d",
3201 			info->name, info->new_version.major, info->new_version.minor, info->new_version.build, info->new_version.revision);
3202 		return;
3203 	}
3204 
3205 	for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
3206 		info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
3207 		if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
3208 			return;
3209 	}
3210 
3211 	info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
3212 	memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
3213 	if (info->name)
3214 		info_copy->name = mono_mempool_strdup (domain->mp, info->name);
3215 	if (info->culture)
3216 		info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
3217 
3218 	domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
3219 }
3220 
3221 static int
get_version_number(int major,int minor)3222 get_version_number (int major, int minor)
3223 {
3224 	return major * 256 + minor;
3225 }
3226 
3227 static inline gboolean
info_major_minor_in_range(MonoAssemblyBindingInfo * info,MonoAssemblyName * aname)3228 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
3229 {
3230 	int aname_version_number = get_version_number (aname->major, aname->minor);
3231 	if (!info->has_old_version_bottom)
3232 		return FALSE;
3233 
3234 	if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
3235 		return FALSE;
3236 
3237 	if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
3238 		return FALSE;
3239 
3240 	/* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
3241 	info->major = aname->major;
3242 	info->minor = aname->minor;
3243 
3244 	return TRUE;
3245 }
3246 
3247 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
3248 static MonoAssemblyBindingInfo*
get_per_domain_assembly_binding_info(MonoDomain * domain,MonoAssemblyName * aname)3249 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
3250 {
3251 	MonoAssemblyBindingInfo *info;
3252 	GSList *list;
3253 
3254 	if (!domain->assembly_bindings)
3255 		return NULL;
3256 
3257 	info = NULL;
3258 	for (list = domain->assembly_bindings; list; list = list->next) {
3259 		info = (MonoAssemblyBindingInfo *)list->data;
3260 		if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
3261 			break;
3262 		info = NULL;
3263 	}
3264 
3265 	if (info) {
3266 		if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
3267 		    info->has_new_version && assembly_binding_maps_name (info, aname))
3268 			info->is_valid = TRUE;
3269 		else
3270 			info->is_valid = FALSE;
3271 	}
3272 
3273 	return info;
3274 }
3275 
3276 void
mono_domain_parse_assembly_bindings(MonoDomain * domain,int amajor,int aminor,gchar * domain_config_file_name)3277 mono_domain_parse_assembly_bindings (MonoDomain *domain, int amajor, int aminor, gchar *domain_config_file_name)
3278 {
3279 	if (domain->assembly_bindings_parsed)
3280 		return;
3281 	mono_domain_lock (domain);
3282 	if (!domain->assembly_bindings_parsed) {
3283 
3284 		gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
3285 
3286 		if (!domain_config_file_path)
3287 			domain_config_file_path = domain_config_file_name;
3288 
3289 		mono_config_parse_assembly_bindings (domain_config_file_path, amajor, aminor, domain, assembly_binding_info_parsed);
3290 		domain->assembly_bindings_parsed = TRUE;
3291 		if (domain_config_file_name != domain_config_file_path)
3292 			g_free (domain_config_file_path);
3293 	}
3294 
3295 	mono_domain_unlock (domain);
3296 }
3297 
3298 static MonoAssemblyName*
mono_assembly_apply_binding(MonoAssemblyName * aname,MonoAssemblyName * dest_name)3299 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3300 {
3301 	MonoError error;
3302 	MonoAssemblyBindingInfo *info, *info2;
3303 	MonoImage *ppimage;
3304 	MonoDomain *domain;
3305 
3306 	if (aname->public_key_token [0] == 0)
3307 		return aname;
3308 
3309 	domain = mono_domain_get ();
3310 
3311 	mono_assembly_binding_lock ();
3312 	info = search_binding_loaded (aname);
3313 	mono_assembly_binding_unlock ();
3314 
3315 	if (!info) {
3316 		mono_domain_lock (domain);
3317 		info = get_per_domain_assembly_binding_info (domain, aname);
3318 		mono_domain_unlock (domain);
3319 	}
3320 
3321 	if (info) {
3322 		if (!check_policy_versions (info, aname))
3323 			return aname;
3324 
3325 		mono_assembly_bind_version (info, aname, dest_name);
3326 		return dest_name;
3327 	}
3328 
3329 	if (domain && domain->setup && domain->setup->configuration_file) {
3330 		gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
3331 		/* expect this to succeed because mono_domain_set_options_from_config () did
3332 		 * the same thing when the domain was created. */
3333 		mono_error_assert_ok (&error);
3334 		mono_domain_parse_assembly_bindings (domain, aname->major, aname->minor, domain_config_file_name);
3335 		g_free (domain_config_file_name);
3336 
3337 		mono_domain_lock (domain);
3338 		info2 = get_per_domain_assembly_binding_info (domain, aname);
3339 
3340 		if (info2) {
3341 			info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
3342 			info->name = g_strdup (info2->name);
3343 			info->culture = g_strdup (info2->culture);
3344 			info->domain_id = domain->domain_id;
3345 		}
3346 
3347 		mono_domain_unlock (domain);
3348 
3349 	}
3350 
3351 	if (!info) {
3352 		info = g_new0 (MonoAssemblyBindingInfo, 1);
3353 		info->major = aname->major;
3354 		info->minor = aname->minor;
3355 	}
3356 
3357 	if (!info->is_valid) {
3358 		ppimage = mono_assembly_load_publisher_policy (aname);
3359 		if (ppimage) {
3360 			get_publisher_policy_info (ppimage, aname, info);
3361 			mono_image_close (ppimage);
3362 		}
3363 	}
3364 
3365 	/* Define default error value if needed */
3366 	if (!info->is_valid) {
3367 		info->name = g_strdup (aname->name);
3368 		info->culture = g_strdup (aname->culture);
3369 		g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3370 	}
3371 
3372 	mono_assembly_binding_lock ();
3373 	info2 = search_binding_loaded (aname);
3374 	if (info2) {
3375 		/* This binding was added by another thread
3376 		 * before us */
3377 		mono_assembly_binding_info_free (info);
3378 		g_free (info);
3379 
3380 		info = info2;
3381 	} else
3382 		loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3383 
3384 	mono_assembly_binding_unlock ();
3385 
3386 	if (!info->is_valid || !check_policy_versions (info, aname))
3387 		return aname;
3388 
3389 	mono_assembly_bind_version (info, aname, dest_name);
3390 	return dest_name;
3391 }
3392 
3393 /**
3394  * mono_assembly_load_from_gac
3395  *
3396  * \param aname The assembly name object
3397  */
3398 static MonoAssembly*
mono_assembly_load_from_gac(MonoAssemblyName * aname,gchar * filename,MonoImageOpenStatus * status,MonoBoolean refonly)3399 mono_assembly_load_from_gac (MonoAssemblyName *aname,  gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3400 {
3401 	MonoAssembly *result = NULL;
3402 	gchar *name, *version, *culture, *fullpath, *subpath;
3403 	gint32 len;
3404 	gchar **paths;
3405 	char *pubtok;
3406 
3407 	if (aname->public_key_token [0] == 0) {
3408 		return NULL;
3409 	}
3410 
3411 	if (strstr (aname->name, ".dll")) {
3412 		len = strlen (filename) - 4;
3413 		name = (gchar *)g_malloc (len + 1);
3414 		memcpy (name, aname->name, len);
3415 		name[len] = 0;
3416 	} else {
3417 		name = g_strdup (aname->name);
3418 	}
3419 
3420 	if (aname->culture) {
3421 		culture = g_utf8_strdown (aname->culture, -1);
3422 	} else {
3423 		culture = g_strdup ("");
3424 	}
3425 
3426 	pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3427 	version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3428 			aname->minor, aname->build, aname->revision,
3429 			culture, pubtok);
3430 	g_free (pubtok);
3431 
3432 	subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3433 	g_free (name);
3434 	g_free (version);
3435 	g_free (culture);
3436 
3437 	if (extra_gac_paths) {
3438 		paths = extra_gac_paths;
3439 		while (!result && *paths) {
3440 			fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3441 			result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3442 			g_free (fullpath);
3443 			paths++;
3444 		}
3445 	}
3446 
3447 	if (result) {
3448 		result->in_gac = TRUE;
3449 		g_free (subpath);
3450 		return result;
3451 	}
3452 
3453 	fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3454 			"mono", "gac", subpath, NULL);
3455 	result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3456 	g_free (fullpath);
3457 
3458 	if (result)
3459 		result->in_gac = TRUE;
3460 
3461 	g_free (subpath);
3462 
3463 	return result;
3464 }
3465 
3466 MonoAssembly*
mono_assembly_load_corlib(const MonoRuntimeInfo * runtime,MonoImageOpenStatus * status)3467 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3468 {
3469 	char *corlib_file;
3470 	MonoAssemblyName *aname;
3471 
3472 	if (corlib) {
3473 		/* g_print ("corlib already loaded\n"); */
3474 		return corlib;
3475 	}
3476 
3477 	// A nonstandard preload hook may provide a special mscorlib assembly
3478 	aname = mono_assembly_name_new ("mscorlib.dll");
3479 	corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3480 	mono_assembly_name_free (aname);
3481 	g_free (aname);
3482 	if (corlib != NULL)
3483 		goto return_corlib_and_facades;
3484 
3485 	// This unusual directory layout can occur if mono is being built and run out of its own source repo
3486 	if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3487 		corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE, NULL, NULL);
3488 		if (corlib)
3489 			goto return_corlib_and_facades;
3490 	}
3491 
3492 	/* Normal case: Load corlib from mono/<version> */
3493 	corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3494 	if (assemblies_path) { // Custom assemblies path
3495 		corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE, NULL, NULL);
3496 		if (corlib) {
3497 			g_free (corlib_file);
3498 			goto return_corlib_and_facades;
3499 		}
3500 	}
3501 	corlib = load_in_path (corlib_file, default_path, status, FALSE, NULL, NULL);
3502 	g_free (corlib_file);
3503 
3504 return_corlib_and_facades:
3505 	if (corlib && !strcmp (runtime->framework_version, "4.5"))  // FIXME: stop hardcoding 4.5 here
3506 		default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3507 
3508 	return corlib;
3509 }
3510 
3511 static MonoAssembly*
prevent_reference_assembly_from_running(MonoAssembly * candidate,gboolean refonly)3512 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly)
3513 {
3514 	MonoError refasm_error;
3515 	error_init (&refasm_error);
3516 	if (candidate && !refonly) {
3517 		/* .NET Framework seems to not check for ReferenceAssemblyAttribute on dynamic assemblies */
3518 		if (!image_is_dynamic (candidate->image) &&
3519 		    mono_assembly_has_reference_assembly_attribute (candidate, &refasm_error))
3520 			candidate = NULL;
3521 	}
3522 	mono_error_cleanup (&refasm_error);
3523 	return candidate;
3524 }
3525 
3526 gboolean
mono_assembly_candidate_predicate_sn_same_name(MonoAssembly * candidate,gpointer ud)3527 mono_assembly_candidate_predicate_sn_same_name (MonoAssembly *candidate, gpointer ud)
3528 {
3529 	MonoAssemblyName *wanted_name = (MonoAssemblyName*)ud;
3530 	MonoAssemblyName *candidate_name = &candidate->aname;
3531 
3532 	g_assert (wanted_name != NULL);
3533 	g_assert (candidate_name != NULL);
3534 
3535 	if (mono_trace_is_traced (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY)) {
3536 		char * s = mono_stringify_assembly_name (wanted_name);
3537 		mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: wanted = %s\n", s);
3538 		g_free (s);
3539 		s = mono_stringify_assembly_name (candidate_name);
3540 		mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate = %s\n", s);
3541 		g_free (s);
3542 	}
3543 
3544 
3545 	/* Wanted name has no token, not strongly named: always matches. */
3546 	if (0 == wanted_name->public_key_token [0]) {
3547 		mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: wanted has no token, returning TRUE\n");
3548 		return TRUE;
3549 	}
3550 
3551 	/* Candidate name has no token, not strongly named: never matches */
3552 	if (0 == candidate_name->public_key_token [0]) {
3553 		mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate has no token, returning FALSE\n");
3554 		return FALSE;
3555 	}
3556 
3557 	return exact_sn_match (wanted_name, candidate_name) ||
3558 		framework_assembly_sn_match (wanted_name, candidate_name);
3559 }
3560 
3561 gboolean
exact_sn_match(MonoAssemblyName * wanted_name,MonoAssemblyName * candidate_name)3562 exact_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name)
3563 {
3564 	gboolean result = mono_assembly_names_equal (wanted_name, candidate_name);
3565 
3566 	mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate and wanted names %s\n",
3567 		    result ? "match, returning TRUE" : "don't match, returning FALSE");
3568 	return result;
3569 
3570 }
3571 
3572 gboolean
framework_assembly_sn_match(MonoAssemblyName * wanted_name,MonoAssemblyName * candidate_name)3573 framework_assembly_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name)
3574 {
3575 #ifndef DISABLE_DESKTOP_LOADER
3576 	const AssemblyVersionMap *vmap = (AssemblyVersionMap *)g_hash_table_lookup (assembly_remapping_table, wanted_name->name);
3577 	if (vmap) {
3578 		if (!vmap->framework_facade_assembly) {
3579 			/* If the wanted name is a framework assembly, it's enough for the name/version/culture to match.  If the assembly was remapped, the public key token is likely unrelated. */
3580 			gboolean result = assembly_names_equal_flags (wanted_name, candidate_name, ANAME_EQ_IGNORE_PUBKEY);
3581 			mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate and wanted names %s (ignoring the public key token)", result ? "match, returning TRUE" : "don't match, returning FALSE");
3582 			return result;
3583 		} else {
3584 			/* For facades, the name and public key token should
3585 			 * match, but the version doesn't matter. */
3586 			gboolean result = assembly_names_equal_flags (wanted_name, candidate_name, ANAME_EQ_IGNORE_VERSION);
3587 			mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate and wanted names %s (ignoring version)", result ? "match, returning TRUE" : "don't match, returning FALSE");
3588 			return result;
3589 		}
3590 	}
3591 #endif
3592 	return FALSE;
3593 }
3594 
3595 MonoAssembly*
mono_assembly_load_full_nosearch(MonoAssemblyName * aname,const char * basedir,MonoImageOpenStatus * status,gboolean refonly)3596 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3597 								  const char       *basedir,
3598 								  MonoImageOpenStatus *status,
3599 								  gboolean refonly)
3600 {
3601 	MonoAssembly *result;
3602 	char *fullpath, *filename;
3603 	MonoAssemblyName maped_aname;
3604 	MonoAssemblyName maped_name_pp;
3605 	int ext_index;
3606 	const char *ext;
3607 	int len;
3608 
3609 	aname = mono_assembly_remap_version (aname, &maped_aname);
3610 
3611 	/* Reflection only assemblies don't get assembly binding */
3612 	if (!refonly)
3613 		aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3614 
3615 	result = mono_assembly_loaded_full (aname, refonly);
3616 	if (result)
3617 		return result;
3618 
3619 	result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3620 	if (result) {
3621 		result->in_gac = FALSE;
3622 		return result;
3623 	}
3624 
3625 	/* Currently we retrieve the loaded corlib for reflection
3626 	 * only requests, like a common reflection only assembly
3627 	 */
3628 	if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3629 		return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3630 	}
3631 
3632 	MonoAssemblyCandidatePredicate predicate = NULL;
3633 	void* predicate_ud = NULL;
3634 #if !defined(DISABLE_DESKTOP_LOADER)
3635 	if (G_LIKELY (mono_loader_get_strict_strong_names ())) {
3636 		predicate = &mono_assembly_candidate_predicate_sn_same_name;
3637 		predicate_ud = aname;
3638 	}
3639 #endif
3640 
3641 	len = strlen (aname->name);
3642 	for (ext_index = 0; ext_index < 2; ext_index ++) {
3643 		ext = ext_index == 0 ? ".dll" : ".exe";
3644 		if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3645 			filename = g_strdup (aname->name);
3646 			/* Don't try appending .dll/.exe if it already has one of those extensions */
3647 			ext_index++;
3648 		} else {
3649 			filename = g_strconcat (aname->name, ext, NULL);
3650 		}
3651 
3652 		result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3653 		if (result) {
3654 			g_free (filename);
3655 			return result;
3656 		}
3657 
3658 		if (basedir) {
3659 			fullpath = g_build_filename (basedir, filename, NULL);
3660 			result = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, predicate_ud, status);
3661 			g_free (fullpath);
3662 			if (result) {
3663 				result->in_gac = FALSE;
3664 				g_free (filename);
3665 				return result;
3666 			}
3667 		}
3668 
3669 		result = load_in_path (filename, default_path, status, refonly, predicate, predicate_ud);
3670 		if (result)
3671 			result->in_gac = FALSE;
3672 		g_free (filename);
3673 		if (result)
3674 			return result;
3675 	}
3676 
3677 	return result;
3678 }
3679 
3680 MonoAssembly*
mono_assembly_load_full_internal(MonoAssemblyName * aname,MonoAssembly * requesting,const char * basedir,MonoImageOpenStatus * status,gboolean refonly)3681 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3682 {
3683 	MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3684 
3685 	if (!result) {
3686 		/* Try a postload search hook */
3687 		result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3688 		result = prevent_reference_assembly_from_running (result, refonly);
3689 	}
3690 	return result;
3691 }
3692 
3693 /**
3694  * mono_assembly_load_full:
3695  * \param aname A MonoAssemblyName with the assembly name to load.
3696  * \param basedir A directory to look up the assembly at.
3697  * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
3698  * \param refonly Whether this assembly is being opened in "reflection-only" mode.
3699  *
3700  * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
3701  * attempts to load the assembly from that directory before probing the standard locations.
3702  *
3703  * If the assembly is being opened in reflection-only mode (\p refonly set to TRUE) then no
3704  * assembly binding takes place.
3705  *
3706  * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
3707  * value pointed by \p status is updated with an error code.
3708  */
3709 MonoAssembly*
mono_assembly_load_full(MonoAssemblyName * aname,const char * basedir,MonoImageOpenStatus * status,gboolean refonly)3710 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3711 {
3712 	return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3713 }
3714 
3715 /**
3716  * mono_assembly_load:
3717  * \param aname A MonoAssemblyName with the assembly name to load.
3718  * \param basedir A directory to look up the assembly at.
3719  * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
3720  *
3721  * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
3722  * attempts to load the assembly from that directory before probing the standard locations.
3723  *
3724  * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
3725  * value pointed by \p status is updated with an error code.
3726  */
3727 MonoAssembly*
mono_assembly_load(MonoAssemblyName * aname,const char * basedir,MonoImageOpenStatus * status)3728 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3729 {
3730 	return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3731 }
3732 
3733 /**
3734  * mono_assembly_loaded_full:
3735  * \param aname an assembly to look for.
3736  * \param refonly Whether this assembly is being opened in "reflection-only" mode.
3737  *
3738  * This is used to determine if the specified assembly has been loaded
3739  * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
3740  * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
3741  */
3742 MonoAssembly*
mono_assembly_loaded_full(MonoAssemblyName * aname,gboolean refonly)3743 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3744 {
3745 	MonoAssembly *res;
3746 	MonoAssemblyName maped_aname;
3747 
3748 	aname = mono_assembly_remap_version (aname, &maped_aname);
3749 
3750 	res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3751 
3752 	return res;
3753 }
3754 
3755 /**
3756  * mono_assembly_loaded:
3757  * \param aname an assembly to look for.
3758  *
3759  * This is used to determine if the specified assembly has been loaded
3760 
3761  * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
3762  * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
3763  */
3764 MonoAssembly*
mono_assembly_loaded(MonoAssemblyName * aname)3765 mono_assembly_loaded (MonoAssemblyName *aname)
3766 {
3767 	return mono_assembly_loaded_full (aname, FALSE);
3768 }
3769 
3770 void
mono_assembly_release_gc_roots(MonoAssembly * assembly)3771 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3772 {
3773 	if (assembly == NULL || assembly == REFERENCE_MISSING)
3774 		return;
3775 
3776 	if (assembly_is_dynamic (assembly)) {
3777 		int i;
3778 		MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3779 		for (i = 0; i < dynimg->image.module_count; ++i)
3780 			mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3781 		mono_dynamic_image_release_gc_roots (dynimg);
3782 	}
3783 }
3784 
3785 /*
3786  * Returns whether mono_assembly_close_finish() must be called as
3787  * well.  See comment for mono_image_close_except_pools() for why we
3788  * unload in two steps.
3789  */
3790 gboolean
mono_assembly_close_except_image_pools(MonoAssembly * assembly)3791 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3792 {
3793 	GSList *tmp;
3794 	g_return_val_if_fail (assembly != NULL, FALSE);
3795 
3796 	if (assembly == REFERENCE_MISSING)
3797 		return FALSE;
3798 
3799 	/* Might be 0 already */
3800 	if (mono_atomic_dec_i32 (&assembly->ref_count) > 0)
3801 		return FALSE;
3802 
3803 	MONO_PROFILER_RAISE (assembly_unloading, (assembly));
3804 
3805 	mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3806 
3807 	mono_debug_close_image (assembly->image);
3808 
3809 	mono_assemblies_lock ();
3810 	loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3811 	mono_assemblies_unlock ();
3812 
3813 	assembly->image->assembly = NULL;
3814 
3815 	if (!mono_image_close_except_pools (assembly->image))
3816 		assembly->image = NULL;
3817 
3818 	for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3819 		MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3820 		mono_assembly_name_free (fname);
3821 		g_free (fname);
3822 	}
3823 	g_slist_free (assembly->friend_assembly_names);
3824 	g_free (assembly->basedir);
3825 
3826 	MONO_PROFILER_RAISE (assembly_unloaded, (assembly));
3827 
3828 	return TRUE;
3829 }
3830 
3831 void
mono_assembly_close_finish(MonoAssembly * assembly)3832 mono_assembly_close_finish (MonoAssembly *assembly)
3833 {
3834 	g_assert (assembly && assembly != REFERENCE_MISSING);
3835 
3836 	if (assembly->image)
3837 		mono_image_close_finish (assembly->image);
3838 
3839 	if (assembly_is_dynamic (assembly)) {
3840 		g_free ((char*)assembly->aname.culture);
3841 	} else {
3842 		g_free (assembly);
3843 	}
3844 }
3845 
3846 /**
3847  * mono_assembly_close:
3848  * \param assembly the assembly to release.
3849  *
3850  * This method releases a reference to the \p assembly.  The assembly is
3851  * only released when all the outstanding references to it are released.
3852  */
3853 void
mono_assembly_close(MonoAssembly * assembly)3854 mono_assembly_close (MonoAssembly *assembly)
3855 {
3856 	if (mono_assembly_close_except_image_pools (assembly))
3857 		mono_assembly_close_finish (assembly);
3858 }
3859 
3860 /**
3861  * mono_assembly_load_module:
3862  */
3863 MonoImage*
mono_assembly_load_module(MonoAssembly * assembly,guint32 idx)3864 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3865 {
3866 	MonoError error;
3867 	MonoImage *result = mono_assembly_load_module_checked (assembly, idx, &error);
3868 	mono_error_assert_ok (&error);
3869 	return result;
3870 }
3871 
3872 MONO_API MonoImage*
mono_assembly_load_module_checked(MonoAssembly * assembly,uint32_t idx,MonoError * error)3873 mono_assembly_load_module_checked (MonoAssembly *assembly, uint32_t idx, MonoError *error)
3874 {
3875 	return mono_image_load_file_for_image_checked (assembly->image, idx, error);
3876 }
3877 
3878 
3879 /**
3880  * mono_assembly_foreach:
3881  * \param func function to invoke for each assembly loaded
3882  * \param user_data data passed to the callback
3883  *
3884  * Invokes the provided \p func callback for each assembly loaded into
3885  * the runtime.   The first parameter passed to the callback  is the
3886  * \c MonoAssembly*, and the second parameter is the \p user_data.
3887  *
3888  * This is done for all assemblies loaded in the runtime, not just
3889  * those loaded in the current application domain.
3890  */
3891 void
mono_assembly_foreach(GFunc func,gpointer user_data)3892 mono_assembly_foreach (GFunc func, gpointer user_data)
3893 {
3894 	GList *copy;
3895 
3896 	/*
3897 	 * We make a copy of the list to avoid calling the callback inside the
3898 	 * lock, which could lead to deadlocks.
3899 	 */
3900 	mono_assemblies_lock ();
3901 	copy = g_list_copy (loaded_assemblies);
3902 	mono_assemblies_unlock ();
3903 
3904 	g_list_foreach (loaded_assemblies, func, user_data);
3905 
3906 	g_list_free (copy);
3907 }
3908 
3909 /**
3910  * mono_assemblies_cleanup:
3911  *
3912  * Free all resources used by this module.
3913  */
3914 void
mono_assemblies_cleanup(void)3915 mono_assemblies_cleanup (void)
3916 {
3917 	GSList *l;
3918 
3919 	mono_os_mutex_destroy (&assemblies_mutex);
3920 	mono_os_mutex_destroy (&assembly_binding_mutex);
3921 
3922 	for (l = loaded_assembly_bindings; l; l = l->next) {
3923 		MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3924 
3925 		mono_assembly_binding_info_free (info);
3926 		g_free (info);
3927 	}
3928 	g_slist_free (loaded_assembly_bindings);
3929 
3930 	free_assembly_load_hooks ();
3931 	free_assembly_search_hooks ();
3932 	free_assembly_preload_hooks ();
3933 }
3934 
3935 /*LOCKING takes the assembly_binding lock*/
3936 void
mono_assembly_cleanup_domain_bindings(guint32 domain_id)3937 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3938 {
3939 	GSList **iter;
3940 
3941 	mono_assembly_binding_lock ();
3942 	iter = &loaded_assembly_bindings;
3943 	while (*iter) {
3944 		GSList *l = *iter;
3945 		MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3946 
3947 		if (info->domain_id == domain_id) {
3948 			*iter = l->next;
3949 			mono_assembly_binding_info_free (info);
3950 			g_free (info);
3951 			g_slist_free_1 (l);
3952 		} else {
3953 			iter = &l->next;
3954 		}
3955 	}
3956 	mono_assembly_binding_unlock ();
3957 }
3958 
3959 /*
3960  * Holds the assembly of the application, for
3961  * System.Diagnostics.Process::MainModule
3962  */
3963 static MonoAssembly *main_assembly=NULL;
3964 
3965 /**
3966  * mono_assembly_set_main:
3967  */
3968 void
mono_assembly_set_main(MonoAssembly * assembly)3969 mono_assembly_set_main (MonoAssembly *assembly)
3970 {
3971 	main_assembly = assembly;
3972 }
3973 
3974 /**
3975  * mono_assembly_get_main:
3976  *
3977  * Returns: the assembly for the application, the first assembly that is loaded by the VM
3978  */
3979 MonoAssembly *
mono_assembly_get_main(void)3980 mono_assembly_get_main (void)
3981 {
3982 	return (main_assembly);
3983 }
3984 
3985 /**
3986  * mono_assembly_get_image:
3987  * \param assembly The assembly to retrieve the image from
3988  *
3989  * \returns the \c MonoImage associated with this assembly.
3990  */
3991 MonoImage*
mono_assembly_get_image(MonoAssembly * assembly)3992 mono_assembly_get_image (MonoAssembly *assembly)
3993 {
3994 	return assembly->image;
3995 }
3996 
3997 /**
3998  * mono_assembly_get_name:
3999  * \param assembly The assembly to retrieve the name from
4000  *
4001  * The returned name's lifetime is the same as \p assembly's.
4002  *
4003  * \returns the \c MonoAssemblyName associated with this assembly.
4004  */
4005 MonoAssemblyName *
mono_assembly_get_name(MonoAssembly * assembly)4006 mono_assembly_get_name (MonoAssembly *assembly)
4007 {
4008 	return &assembly->aname;
4009 }
4010 
4011 /**
4012  * mono_register_bundled_assemblies:
4013  */
4014 void
mono_register_bundled_assemblies(const MonoBundledAssembly ** assemblies)4015 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
4016 {
4017 	bundles = assemblies;
4018 }
4019 
4020 #define MONO_DECLSEC_FORMAT_10		0x3C
4021 #define MONO_DECLSEC_FORMAT_20		0x2E
4022 #define MONO_DECLSEC_FIELD		0x53
4023 #define MONO_DECLSEC_PROPERTY		0x54
4024 
4025 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
4026 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
4027 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
4028 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
4029 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
4030 
4031 static gboolean
mono_assembly_try_decode_skip_verification_param(const char * p,const char ** resp,gboolean * abort_decoding)4032 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
4033 {
4034 	int len;
4035 	switch (*p++) {
4036 	case MONO_DECLSEC_PROPERTY:
4037 		break;
4038 	case MONO_DECLSEC_FIELD:
4039 	default:
4040 		*abort_decoding = TRUE;
4041 		return FALSE;
4042 		break;
4043 	}
4044 
4045 	if (*p++ != MONO_TYPE_BOOLEAN) {
4046 		*abort_decoding = TRUE;
4047 		return FALSE;
4048 	}
4049 
4050 	/* property name length */
4051 	len = mono_metadata_decode_value (p, &p);
4052 
4053 	if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
4054 		p += len;
4055 		return *p;
4056 	}
4057 	p += len + 1;
4058 
4059 	*resp = p;
4060 	return FALSE;
4061 }
4062 
4063 static gboolean
mono_assembly_try_decode_skip_verification(const char * p,const char * endn)4064 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
4065 {
4066 	int i, j, num, len, params_len;
4067 
4068 	if (*p == MONO_DECLSEC_FORMAT_10) {
4069 		gsize read, written;
4070 		char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
4071 		if (res) {
4072 			gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
4073 			g_free (res);
4074 			return found;
4075 		}
4076 		return FALSE;
4077 	}
4078 	if (*p++ != MONO_DECLSEC_FORMAT_20)
4079 		return FALSE;
4080 
4081 	/* number of encoded permission attributes */
4082 	num = mono_metadata_decode_value (p, &p);
4083 	for (i = 0; i < num; ++i) {
4084 		gboolean is_valid = FALSE;
4085 		gboolean abort_decoding = FALSE;
4086 
4087 		/* attribute name length */
4088 		len =  mono_metadata_decode_value (p, &p);
4089 
4090 		/* We don't really need to fully decode the type. Comparing the name is enough */
4091 		is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
4092 
4093 		p += len;
4094 
4095 		/*size of the params table*/
4096 		params_len =  mono_metadata_decode_value (p, &p);
4097 		if (is_valid) {
4098 			const char *params_end = p + params_len;
4099 
4100 			/* number of parameters */
4101 			len = mono_metadata_decode_value (p, &p);
4102 
4103 			for (j = 0; j < len; ++j) {
4104 				if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
4105 					return TRUE;
4106 				if (abort_decoding)
4107 					break;
4108 			}
4109 			p = params_end;
4110 		} else {
4111 			p += params_len;
4112 		}
4113 	}
4114 
4115 	return FALSE;
4116 }
4117 
4118 
4119 gboolean
mono_assembly_has_skip_verification(MonoAssembly * assembly)4120 mono_assembly_has_skip_verification (MonoAssembly *assembly)
4121 {
4122 	MonoTableInfo *t;
4123 	guint32 cols [MONO_DECL_SECURITY_SIZE];
4124 	const char *blob;
4125 	int i, len;
4126 
4127 	if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
4128 		return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
4129 
4130 	t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
4131 
4132 	for (i = 0; i < t->rows; ++i) {
4133 		mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
4134 		if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
4135 			continue;
4136 		if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
4137 			continue;
4138 
4139 		blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
4140 		len = mono_metadata_decode_blob_size (blob, &blob);
4141 		if (!len)
4142 			continue;
4143 
4144 		if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
4145 			MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
4146 			return TRUE;
4147 		}
4148 	}
4149 
4150 	MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);
4151 	return FALSE;
4152 }
4153