HMODULE LoadCoreClrFromPath(const std::wstring& coreclr_dir, dnx::trace_writer& trace_writer) { auto loader_module = LoadLoaderModule(trace_writer); if (!loader_module) { trace_writer.write(L"Failed to load loader module", false); return nullptr; } auto pfnAddDllDirectory = (FnAddDllDirectory)GetProcAddress(loader_module, "AddDllDirectory"); auto pfnSetDefaultDllDirectories = (FnSetDefaultDllDirectories)GetProcAddress(loader_module, "SetDefaultDllDirectories"); if (!pfnAddDllDirectory || !pfnSetDefaultDllDirectories) { trace_writer.write(std::wstring(L"Failed to find function: ") .append(pfnAddDllDirectory ? L"SetDefaultDllDirectories" : L"AddDllDirectory"), false); return nullptr; } pfnAddDllDirectory(coreclr_dir.c_str()); // Modify the default dll flags so that dependencies can be found in this path pfnSetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_USER_DIRS); return LoadLibraryExW(dnx::utils::path_combine(coreclr_dir, L"coreclr.dll").c_str(), NULL, 0); }
int CallApplicationMain(const wchar_t* moduleName, const char* functionName, CALL_APPLICATION_MAIN_DATA* data, dnx::trace_writer& trace_writer) { HMODULE hostModule = nullptr; try { const auto runtime_new_path = get_runtime_path(trace_writer); if (runtime_new_path.length() > 0) { trace_writer.write(std::wstring(L"Redirecting runtime to: ").append(runtime_new_path), true); SetEnvironmentVariable(_T("DNX_DEFAULT_LIB"), runtime_new_path.c_str()); #if defined(CORECLR_WIN) SetEnvironmentVariable(_T("CORECLR_DIR"), runtime_new_path.c_str()); data->runtimeDirectory = runtime_new_path.c_str(); #endif } auto module_path = dnx::utils::path_combine(runtime_new_path, moduleName); hostModule = LoadLibraryEx(module_path.c_str(), NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); if (!hostModule) { throw std::runtime_error(std::string("Failed to load: ") .append(dnx::utils::to_string(moduleName))); } trace_writer.write(std::wstring(L"Loaded module: ").append(module_path), true); auto pfnCallApplicationMain = reinterpret_cast<FnCallApplicationMain>(GetProcAddress(hostModule, functionName)); if (!pfnCallApplicationMain) { std::ostringstream oss; oss << "Failed to find export '" << functionName << "' in " << dnx::utils::to_string(moduleName); throw std::runtime_error(oss.str()); } trace_writer.write(std::wstring(L"Found export: ").append(dnx::utils::to_wstring(functionName)), true); HRESULT hr = pfnCallApplicationMain(data); FreeLibrary(hostModule); return SUCCEEDED(hr) ? data->exitcode : hr; } catch (...) { if (hostModule) { FreeLibrary(hostModule); } throw; } }
/* Win2KDisable : DisallowWin32kSystemCalls SET DNX_WIN32K_DISABLE=1 */ void Win32KDisable(dnx::trace_writer& trace_writer) { wchar_t buff[2] = { 0 , 0 }; if (GetEnvironmentVariable(L"DNX_WIN32K_DISABLE", buff, 2) != 1 || buff[0] != L'1') { return; } auto process_threads_module = LoadLibraryExW(L"api-ms-win-core-processthreads-l1-1-1.dll", NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); if (process_threads_module) { auto SetProcessMitigationPolicy_function = (FnSetProcessMitigationPolicy)GetProcAddress(process_threads_module, "SetProcessMitigationPolicy"); if (SetProcessMitigationPolicy_function) { PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY system_call_disable_policy = {}; system_call_disable_policy.DisallowWin32kSystemCalls = 1; if (SetProcessMitigationPolicy_function(ProcessSystemCallDisablePolicy, &system_call_disable_policy, sizeof(system_call_disable_policy))) { trace_writer.write(L"DNX_WIN32K_DISABLE successful", false); } } } FreeLibrary(process_threads_module); }
HMODULE LoadCoreClr(const std::wstring& runtime_directory, dnx::trace_writer& trace_writer) { HMODULE coreclr_module; wchar_t coreclr_dir_buffer[MAX_PATH]; auto result = GetEnvironmentVariableW(L"CORECLR_DIR", coreclr_dir_buffer, MAX_PATH); if (result > MAX_PATH) { trace_writer.write(L"The value of the 'CORECLR_DIR' variable is invalid. Aborting loading coreclr.dll.", true); return nullptr; } if (result) { coreclr_module = LoadCoreClrFromPath(coreclr_dir_buffer, trace_writer); } else { coreclr_module = LoadLibraryExW(dnx::utils::path_combine(runtime_directory, L"coreclr.dll").c_str(), NULL, 0); } if (coreclr_module) { if (PinModule(coreclr_module, trace_writer)) { return coreclr_module; } FreeLibrary(coreclr_module); } return nullptr; }
HRESULT GetClrRuntimeHost(HMODULE coreclr_module, ICLRRuntimeHost2** ppClrRuntimeHost, dnx::trace_writer& trace_writer) { auto GetCLRRuntimeHost_function = (FnGetCLRRuntimeHost)GetProcAddress(coreclr_module, "GetCLRRuntimeHost"); if (!GetCLRRuntimeHost_function) { trace_writer.write(L"Failed to find export GetCLRRuntimeHost", false); return E_FAIL; } return GetCLRRuntimeHost_function(IID_ICLRRuntimeHost2, (IUnknown**)ppClrRuntimeHost); }
int CallApplicationMain(const char* moduleName, const char* functionName, CALL_APPLICATION_MAIN_DATA* data, dnx::trace_writer& trace_writer) { auto localPath = GetNativeBootstrapperDirectory().append("/").append(moduleName); void* host = nullptr; try { host = dlopen(localPath.c_str(), RTLD_NOW | RTLD_GLOBAL); if (!host) { throw std::runtime_error(std::string("Failed to load: ").append(moduleName)); } trace_writer.write(std::string("Loaded module: ").append(moduleName), true); auto pfnCallApplicationMain = reinterpret_cast<FnCallApplicationMain>(dlsym(host, functionName)); if (!pfnCallApplicationMain) { std::ostringstream oss; oss << "Failed to find export '" << functionName << "' in " << moduleName; throw std::runtime_error(oss.str()); } trace_writer.write(std::string("Found export: ").append(functionName), true); auto result = pfnCallApplicationMain(data); dlclose(host); return result == 0 ? data->exitcode : result; } catch(const std::exception& ex) { if(host) { dlclose(host); } throw; } }
bool PinModule(HMODULE module, dnx::trace_writer& trace_writer) { wchar_t module_path_buffer[MAX_PATH]; GetModuleFileName(module, module_path_buffer, MAX_PATH); HMODULE ignoreModule; // Pin the module - CoreCLR.dll does not support being unloaded. if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_PIN, module_path_buffer, &ignoreModule)) { trace_writer.write(L"Failed to pin coreclr.dll", false); return false; } return true; }
HMODULE LoadLoaderModule(dnx::trace_writer& trace_writer) { const wchar_t* module_names[] = { L"api-ms-win-core-libraryloader-l1-1-1.dll", L"kernel32.dll", }; for (auto i = 0; i < sizeof(module_names) / sizeof(wchar_t*); i++) { auto loader_module = LoadLibraryExW(module_names[i], NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); if (loader_module) { trace_writer.write(std::wstring(L"Loaded ").append(module_names[i]), true); return loader_module; } } return nullptr; }
HRESULT StartClrHost(ICLRRuntimeHost2* pCLRRuntimeHost, dnx::trace_writer& trace_writer) { STARTUP_FLAGS startup_flags = (STARTUP_FLAGS)( STARTUP_FLAGS::STARTUP_LOADER_OPTIMIZATION_SINGLE_DOMAIN | STARTUP_FLAGS::STARTUP_SINGLE_APPDOMAIN // STARTUP_SERVER_GC flag is not supported by CoreCLR for ARM #ifndef ARM | STARTUP_FLAGS::STARTUP_SERVER_GC #endif ); pCLRRuntimeHost->SetStartupFlags(startup_flags); // Authenticate with either CORECLR_HOST_AUTHENTICATION_KEY or CORECLR_HOST_AUTHENTICATION_KEY_NONGEN HRESULT hr = pCLRRuntimeHost->Authenticate(CORECLR_HOST_AUTHENTICATION_KEY); if (FAILED(hr)) { trace_writer.write(L"Failed to Authenticate()", false); return hr; } return pCLRRuntimeHost->Start(); }
HRESULT ExecuteMain(ICLRRuntimeHost2* pCLRRuntimeHost, PCALL_APPLICATION_MAIN_DATA data, const std::wstring& runtime_directory, const std::wstring& core_clr_directory, dnx::trace_writer& trace_writer) { const wchar_t* property_keys[] = { // Allowed property names: // APPBASE // - The base path of the application from which the exe and other assemblies will be loaded L"APPBASE", // // TRUSTED_PLATFORM_ASSEMBLIES // - The list of complete paths to each of the fully trusted assemblies L"TRUSTED_PLATFORM_ASSEMBLIES", // // APP_PATHS // - The list of paths which will be probed by the assembly loader L"APP_PATHS", // // APP_NI_PATHS // - The list of additional paths that the assembly loader will probe for ngen images // // NATIVE_DLL_SEARCH_DIRECTORIES // - The list of paths that will be probed for native DLLs called by PInvoke // L"AppDomainCompatSwitch", }; std::wstring trusted_platform_assemblies; // Came up with 8192 empirically - the string we build is about 4000 characters on my machine but it contains // paths to the user profile folder so it can be bigger. trusted_platform_assemblies.reserve(8192); // Try native images first if (!GetTrustedPlatformAssembliesList(core_clr_directory, true, trusted_platform_assemblies)) { if (!GetTrustedPlatformAssembliesList(core_clr_directory, false, trusted_platform_assemblies)) { trace_writer.write(L"Failed to find TPA files in the coreclr directory", false); return E_FAIL; } } // Add the assembly containing the app domain manager to the trusted list trusted_platform_assemblies.append(dnx::utils::path_combine(runtime_directory, L"Microsoft.Dnx.Host.CoreClr.dll")); std::wstring app_paths; app_paths.append(runtime_directory).append(L";"); app_paths.append(core_clr_directory).append(L";"); const wchar_t* property_values[] = { // APPBASE data->applicationBase, // TRUSTED_PLATFORM_ASSEMBLIES trusted_platform_assemblies.c_str(), // APP_PATHS app_paths.c_str(), // Use the latest behavior when TFM not specified L"UseLatestBehaviorWhenTFMNotSpecified", }; DWORD domainId; HRESULT hr = pCLRRuntimeHost->CreateAppDomainWithManager( L"Microsoft.Dnx.Host.CoreClr", APPDOMAIN_ENABLE_PLATFORM_SPECIFIC_APPS | APPDOMAIN_ENABLE_PINVOKE_AND_CLASSIC_COMINTEROP | APPDOMAIN_DISABLE_TRANSPARENCY_ENFORCEMENT, NULL, NULL, sizeof(property_keys) / sizeof(wchar_t*), property_keys, property_values, &domainId); if (FAILED(hr)) { trace_writer.write(L"Failed to create app domain", false); trace_writer.write(std::wstring(L"TPA: ").append(trusted_platform_assemblies), false); trace_writer.write(std::wstring(L"AppPaths: ").append(app_paths), false); return hr; } HostMain main_function; // looks like the Version in the assembly is mandatory but the value does not matter hr = pCLRRuntimeHost->CreateDelegate(domainId, L"Microsoft.Dnx.Host.CoreClr, Version=0.0.0.0", L"DomainManager", L"Execute", (INT_PTR*)&main_function); if (FAILED(hr)) { trace_writer.write(L"Failed to create main delegate", false); return hr; } // Call main data->exitcode = main_function(data->argc, data->argv); pCLRRuntimeHost->UnloadAppDomain(domainId, true); return S_OK; }
std::wstring get_runtime_path(const std::wstring& servicing_root_parent, bool is_default_servicing_location, dnx::trace_writer& trace_writer) { auto servicing_root = is_default_servicing_location ? utils::path_combine(servicing_root_parent, std::wstring(L"Microsoft DNX\\Servicing")) : servicing_root_parent; auto servicing_root_exists = utils::directory_exists(servicing_root); if (!servicing_root_exists) { if (require_servicing()) { throw std::runtime_error("Servicing is required for the application to run but the servicing folder does not exist."); } if (is_default_servicing_location) { trace_writer.write(L"The default servicing root does not exist.", true); return std::wstring{}; } } if (!is_default_servicing_location && is_network_path(servicing_root)) { throw std::runtime_error("Network paths cannot be used as servicing roots."); } auto servicing_manifest_path = utils::path_combine(servicing_root, std::wstring(L"index.txt")); if (!utils::file_exists(servicing_manifest_path)) { throw std::runtime_error("The servicing index does not exist or is not accessible."); } for (auto i = 0; i < 3; i++) { trace_writer.write(std::wstring(L"Reading servicing index file - attempt: ") .append(dnx::utils::to_xstring_t(std::to_string(i + 1))).append(L" of 3"), true); // index.txt is ASCII std::ifstream servicing_manifest; servicing_manifest.open(servicing_manifest_path, std::ifstream::in); if (servicing_manifest.is_open()) { trace_writer.write(std::wstring(L"Found servicing index file at: ").append(servicing_manifest_path), true); auto reading_successful = true; auto runtime_replacement_path = find_runtime_replacement(servicing_manifest, trace_writer, reading_successful); if (reading_successful) { if (runtime_replacement_path.length() > 0) { return get_full_replacement_path(servicing_root, runtime_replacement_path); } trace_writer.write(L"No runtime redirections found.", true); return std::wstring{}; } std::this_thread::sleep_for(std::chrono::milliseconds(100)); } } throw std::runtime_error("The servicing index file could not be opened or read."); }