VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/win/ldrNative-win.cpp@ 61503

Last change on this file since 61503 was 59396, checked in by vboxsync, 9 years ago

ldrNative-win.cpp: Implemented loading system dlls from WinSxS.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 11.3 KB
Line 
1/* $Id: ldrNative-win.cpp 59396 2016-01-19 03:32:03Z vboxsync $ */
2/** @file
3 * IPRT - Binary Image Loader, Win32 native.
4 */
5
6/*
7 * Copyright (C) 2006-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#define LOG_GROUP RTLOGGROUP_LDR
32#include <iprt/nt/nt-and-windows.h>
33
34#include <iprt/ldr.h>
35#include "internal/iprt.h"
36
37#include <iprt/alloca.h>
38#include <iprt/assert.h>
39#include <iprt/ctype.h>
40#include <iprt/err.h>
41#include <iprt/file.h>
42#include <iprt/log.h>
43#include <iprt/path.h>
44#include <iprt/string.h>
45
46#include <iprt/once.h>
47#include <iprt/string.h>
48#include "internal/ldr.h"
49#include "internal-r3-win.h"
50
51#ifndef LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR
52# define LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR UINT32_C(0x100)
53# define LOAD_LIBRARY_SEARCH_APPLICATION_DIR UINT32_C(0x200)
54# define LOAD_LIBRARY_SEARCH_SYSTEM32 UINT32_C(0x800)
55#endif
56
57
58int rtldrNativeLoad(const char *pszFilename, uintptr_t *phHandle, uint32_t fFlags, PRTERRINFO pErrInfo)
59{
60 Assert(sizeof(*phHandle) >= sizeof(HMODULE));
61 AssertReturn(!(fFlags & RTLDRLOAD_FLAGS_GLOBAL), VERR_INVALID_FLAGS);
62 AssertLogRelMsgReturn(RTPathStartsWithRoot(pszFilename), /* Relative names will still be applied to the search path. */
63 ("pszFilename='%s'\n", pszFilename),
64 VERR_INTERNAL_ERROR_2);
65 AssertReleaseMsg(g_hModKernel32,
66 ("rtldrNativeLoad(%s,,) is called before IPRT has configured the windows loader!\n", pszFilename));
67
68 /*
69 * Convert to UTF-16 and make sure it got a .DLL suffix.
70 */
71 int rc;
72 RTUTF16 *pwszNative = NULL;
73 if (RTPathHasSuffix(pszFilename))
74 rc = RTStrToUtf16(pszFilename, &pwszNative);
75 else
76 {
77 size_t cwcAlloc;
78 rc = RTStrCalcUtf16LenEx(pszFilename, RTSTR_MAX, &cwcAlloc);
79 if (RT_SUCCESS(rc))
80 {
81 cwcAlloc += sizeof(".DLL");
82 pwszNative = RTUtf16Alloc(cwcAlloc * sizeof(RTUTF16));
83 if (pwszNative)
84 {
85 size_t cwcNative;
86 rc = RTStrToUtf16Ex(pszFilename, RTSTR_MAX, &pwszNative, cwcAlloc, &cwcNative);
87 if (RT_SUCCESS(rc))
88 rc = RTUtf16CopyAscii(&pwszNative[cwcNative], cwcAlloc - cwcNative, ".DLL");
89 }
90 else
91 rc = VERR_NO_UTF16_MEMORY;
92 }
93 }
94 if (RT_SUCCESS(rc))
95 {
96 /*
97 * Attempt load.
98 */
99 HMODULE hmod;
100 static int s_iSearchDllLoadDirSupported = 0;
101 if ( !(fFlags & RTLDRLOAD_FLAGS_NT_SEARCH_DLL_LOAD_DIR)
102 || s_iSearchDllLoadDirSupported < 0)
103 hmod = LoadLibraryExW(pwszNative, NULL, 0);
104 else
105 {
106 hmod = LoadLibraryExW(pwszNative, NULL, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32
107 | LOAD_LIBRARY_SEARCH_APPLICATION_DIR);
108 if (s_iSearchDllLoadDirSupported == 0)
109 {
110 if (hmod != NULL || GetLastError() != ERROR_INVALID_PARAMETER)
111 s_iSearchDllLoadDirSupported = 1;
112 else
113 {
114 s_iSearchDllLoadDirSupported = -1;
115 hmod = LoadLibraryExW(pwszNative, NULL, 0);
116 }
117 }
118 }
119 if (hmod)
120 {
121 *phHandle = (uintptr_t)hmod;
122 RTUtf16Free(pwszNative);
123 return VINF_SUCCESS;
124 }
125
126 /*
127 * Try figure why it failed to load.
128 */
129 DWORD dwErr = GetLastError();
130 rc = RTErrConvertFromWin32(dwErr);
131 rc = RTErrInfoSetF(pErrInfo, rc, "GetLastError=%u", dwErr);
132 }
133 else
134 rc = RTErrInfoSetF(pErrInfo, rc, "Error converting UTF-8 to UTF-16 string.");
135 RTUtf16Free(pwszNative);
136 return rc;
137}
138
139
140DECLCALLBACK(int) rtldrNativeGetSymbol(PRTLDRMODINTERNAL pMod, const char *pszSymbol, void **ppvValue)
141{
142 PRTLDRMODNATIVE pModNative = (PRTLDRMODNATIVE)pMod;
143 FARPROC pfn = GetProcAddress((HMODULE)pModNative->hNative, pszSymbol);
144 if (pfn)
145 {
146 *ppvValue = (void *)pfn;
147 return VINF_SUCCESS;
148 }
149 *ppvValue = NULL;
150 return RTErrConvertFromWin32(GetLastError());
151}
152
153
154DECLCALLBACK(int) rtldrNativeClose(PRTLDRMODINTERNAL pMod)
155{
156 PRTLDRMODNATIVE pModNative = (PRTLDRMODNATIVE)pMod;
157 if ( (pModNative->fFlags & RTLDRLOAD_FLAGS_NO_UNLOAD)
158 || FreeLibrary((HMODULE)pModNative->hNative))
159 {
160 pModNative->hNative = (uintptr_t)INVALID_HANDLE_VALUE;
161 return VINF_SUCCESS;
162 }
163 return RTErrConvertFromWin32(GetLastError());
164}
165
166
167int rtldrNativeLoadSystem(const char *pszFilename, const char *pszExt, uint32_t fFlags, PRTLDRMOD phLdrMod)
168{
169 AssertReleaseMsg(g_hModKernel32,
170 ("rtldrNativeLoadSystem(%s,,) is called before IPRT has configured the windows loader!\n", pszFilename));
171
172 /*
173 * Resolve side-by-side resolver API.
174 */
175 static bool volatile s_fInitialized = false;
176 static decltype(RtlDosApplyFileIsolationRedirection_Ustr) *s_pfnApplyRedir = NULL;
177 if (!s_fInitialized)
178 {
179 s_pfnApplyRedir = (decltype(s_pfnApplyRedir))GetProcAddress(g_hModNtDll,
180 "RtlDosApplyFileIsolationRedirection_Ustr");
181 ASMCompilerBarrier();
182 s_fInitialized = true;
183 }
184
185 /*
186 * We try WinSxS via undocumented NTDLL API and flal back on the System32
187 * directory. No other locations are supported.
188 */
189 int rc = VERR_TRY_AGAIN;
190 char szPath[RTPATH_MAX];
191 char *pszPath = szPath;
192
193 /* Get the windows system32 directory so we can sanity check the WinSxS result. */
194 WCHAR wszSysDir[MAX_PATH];
195 UINT cwcSysDir = GetSystemDirectoryW(wszSysDir, MAX_PATH);
196 if (cwcSysDir >= MAX_PATH)
197 return VERR_FILENAME_TOO_LONG;
198
199 /* Try side-by-side first (see COMCTL32.DLL). */
200 if (s_pfnApplyRedir)
201 {
202 size_t cwcName = 0;
203 RTUTF16 wszName[MAX_PATH];
204 PRTUTF16 pwszName = wszName;
205 int rc2 = RTStrToUtf16Ex(pszFilename, RTSTR_MAX, &pwszName, RT_ELEMENTS(wszName), &cwcName);
206 if (RT_SUCCESS(rc2))
207 {
208 static UNICODE_STRING const s_DefaultSuffix = RTNT_CONSTANT_UNISTR(L".dll");
209 WCHAR wszPath[MAX_PATH];
210 UNICODE_STRING UniStrStatic = { 0, (USHORT)sizeof(wszPath) - sizeof(WCHAR), wszPath };
211 UNICODE_STRING UniStrDynamic = { 0, 0, NULL };
212 PUNICODE_STRING pUniStrResult = NULL;
213 UNICODE_STRING UniStrName =
214 { (USHORT)(cwcName * sizeof(RTUTF16)), (USHORT)((cwcName + 1) * sizeof(RTUTF16)), wszName };
215
216 NTSTATUS rcNt = s_pfnApplyRedir(1 /*fFlags*/,
217 &UniStrName,
218 (PUNICODE_STRING)&s_DefaultSuffix,
219 &UniStrStatic,
220 &UniStrDynamic,
221 &pUniStrResult,
222 NULL /*pNewFlags*/,
223 NULL /*pcbFilename*/,
224 NULL /*pcbNeeded*/);
225 if (NT_SUCCESS(rcNt))
226 {
227 /*
228 * Check that the resolved path has similarities to the
229 * system directory.
230 *
231 * ASSUMES the windows directory is a root directory and
232 * that both System32 and are on the same level. So, we'll
233 * have 2 matching components (or more if the resolver
234 * returns a system32 path for some reason).
235 */
236 unsigned cMatchingComponents = 0;
237 unsigned cSlashes = 0;
238 size_t off = 0;
239 while (off < pUniStrResult->Length)
240 {
241 RTUTF16 wc1 = wszSysDir[off];
242 RTUTF16 wc2 = pUniStrResult->Buffer[off];
243 if (!RTPATH_IS_SLASH(wc1))
244 {
245 if (wc1 == wc2)
246 off++;
247 else if ( wc1 < 127
248 && wc2 < 127
249 && RT_C_TO_LOWER(wc1) == RT_C_TO_LOWER(wc2) )
250 off++;
251 else
252 break;
253 }
254 else if (RTPATH_IS_SLASH(wc2))
255 {
256 cMatchingComponents += off > 0;
257 do
258 off++;
259 while ( off < pUniStrResult->Length
260 && RTPATH_IS_SLASH(wszSysDir[off])
261 && RTPATH_IS_SLASH(pUniStrResult->Buffer[off]));
262 }
263 else
264 break;
265 }
266 if (cMatchingComponents >= 2)
267 {
268 pszPath = szPath;
269 rc2 = RTUtf16ToUtf8Ex(pUniStrResult->Buffer, pUniStrResult->Length / sizeof(RTUTF16),
270 &pszPath, sizeof(szPath), NULL);
271 if (RT_SUCCESS(rc2))
272 rc = VINF_SUCCESS;
273 }
274 else
275 AssertMsgFailed(("%s -> '%*.ls'\n", pszFilename, pUniStrResult->Length, pUniStrResult->Buffer));
276 RtlFreeUnicodeString(&UniStrDynamic);
277 }
278 }
279 else
280 AssertMsgFailed(("%Rrc\n", rc));
281 }
282
283 /* If the above didn't succeed, create a system32 path. */
284 if (RT_FAILURE(rc))
285 {
286 rc = RTUtf16ToUtf8Ex(wszSysDir, RTSTR_MAX, &pszPath, sizeof(szPath), NULL);
287 if (RT_SUCCESS(rc))
288 {
289 rc = RTPathAppend(szPath, sizeof(szPath), pszFilename);
290 if (pszExt && RT_SUCCESS(rc))
291 rc = RTStrCat(szPath, sizeof(szPath), pszExt);
292 }
293 }
294
295 /* Do the actual loading, if we were successful constructing a name. */
296 if (RT_SUCCESS(rc))
297 {
298 if (RTFileExists(szPath))
299 rc = RTLdrLoadEx(szPath, phLdrMod, fFlags, NULL);
300 else
301 rc = VERR_MODULE_NOT_FOUND;
302 }
303
304 return rc;
305}
306
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette