VirtualBox

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

Last change on this file since 71150 was 69111, checked in by vboxsync, 7 years ago

(C) year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 11.5 KB
Line 
1/* $Id: ldrNative-win.cpp 69111 2017-10-17 14:26:02Z vboxsync $ */
2/** @file
3 * IPRT - Binary Image Loader, Win32 native.
4 */
5
6/*
7 * Copyright (C) 2006-2017 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 /* Convert slashes just to be on the safe side. */
97 for (size_t off = 0;; off++)
98 {
99 RTUTF16 wc = pwszNative[off];
100 if (wc == '/')
101 pwszNative[off] = '\\';
102 else if (!wc)
103 break;
104 }
105
106 /*
107 * Attempt load.
108 */
109 HMODULE hmod;
110 static int s_iSearchDllLoadDirSupported = 0;
111 if ( !(fFlags & RTLDRLOAD_FLAGS_NT_SEARCH_DLL_LOAD_DIR)
112 || s_iSearchDllLoadDirSupported < 0)
113 hmod = LoadLibraryExW(pwszNative, NULL, 0);
114 else
115 {
116 hmod = LoadLibraryExW(pwszNative, NULL, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32
117 | LOAD_LIBRARY_SEARCH_APPLICATION_DIR);
118 if (s_iSearchDllLoadDirSupported == 0)
119 {
120 if (hmod != NULL || GetLastError() != ERROR_INVALID_PARAMETER)
121 s_iSearchDllLoadDirSupported = 1;
122 else
123 {
124 s_iSearchDllLoadDirSupported = -1;
125 hmod = LoadLibraryExW(pwszNative, NULL, 0);
126 }
127 }
128 }
129 if (hmod)
130 {
131 *phHandle = (uintptr_t)hmod;
132 RTUtf16Free(pwszNative);
133 return VINF_SUCCESS;
134 }
135
136 /*
137 * Try figure why it failed to load.
138 */
139 DWORD dwErr = GetLastError();
140 rc = RTErrConvertFromWin32(dwErr);
141 rc = RTErrInfoSetF(pErrInfo, rc, "GetLastError=%u", dwErr);
142 }
143 else
144 rc = RTErrInfoSetF(pErrInfo, rc, "Error converting UTF-8 to UTF-16 string.");
145 RTUtf16Free(pwszNative);
146 return rc;
147}
148
149
150DECLCALLBACK(int) rtldrNativeGetSymbol(PRTLDRMODINTERNAL pMod, const char *pszSymbol, void **ppvValue)
151{
152 PRTLDRMODNATIVE pModNative = (PRTLDRMODNATIVE)pMod;
153 FARPROC pfn = GetProcAddress((HMODULE)pModNative->hNative, pszSymbol);
154 if (pfn)
155 {
156 *ppvValue = (void *)pfn;
157 return VINF_SUCCESS;
158 }
159 *ppvValue = NULL;
160 return RTErrConvertFromWin32(GetLastError());
161}
162
163
164DECLCALLBACK(int) rtldrNativeClose(PRTLDRMODINTERNAL pMod)
165{
166 PRTLDRMODNATIVE pModNative = (PRTLDRMODNATIVE)pMod;
167 if ( (pModNative->fFlags & RTLDRLOAD_FLAGS_NO_UNLOAD)
168 || FreeLibrary((HMODULE)pModNative->hNative))
169 {
170 pModNative->hNative = (uintptr_t)INVALID_HANDLE_VALUE;
171 return VINF_SUCCESS;
172 }
173 return RTErrConvertFromWin32(GetLastError());
174}
175
176
177int rtldrNativeLoadSystem(const char *pszFilename, const char *pszExt, uint32_t fFlags, PRTLDRMOD phLdrMod)
178{
179 AssertReleaseMsg(g_hModKernel32,
180 ("rtldrNativeLoadSystem(%s,,) is called before IPRT has configured the windows loader!\n", pszFilename));
181
182 /*
183 * Resolve side-by-side resolver API.
184 */
185 static bool volatile s_fInitialized = false;
186 static decltype(RtlDosApplyFileIsolationRedirection_Ustr) *s_pfnApplyRedir = NULL;
187 if (!s_fInitialized)
188 {
189 s_pfnApplyRedir = (decltype(s_pfnApplyRedir))GetProcAddress(g_hModNtDll,
190 "RtlDosApplyFileIsolationRedirection_Ustr");
191 ASMCompilerBarrier();
192 s_fInitialized = true;
193 }
194
195 /*
196 * We try WinSxS via undocumented NTDLL API and flal back on the System32
197 * directory. No other locations are supported.
198 */
199 int rc = VERR_TRY_AGAIN;
200 char szPath[RTPATH_MAX];
201 char *pszPath = szPath;
202
203 /* Get the windows system32 directory so we can sanity check the WinSxS result. */
204 WCHAR wszSysDir[MAX_PATH];
205 UINT cwcSysDir = GetSystemDirectoryW(wszSysDir, MAX_PATH);
206 if (cwcSysDir >= MAX_PATH)
207 return VERR_FILENAME_TOO_LONG;
208
209 /* Try side-by-side first (see COMCTL32.DLL). */
210 if (s_pfnApplyRedir)
211 {
212 size_t cwcName = 0;
213 RTUTF16 wszName[MAX_PATH];
214 PRTUTF16 pwszName = wszName;
215 int rc2 = RTStrToUtf16Ex(pszFilename, RTSTR_MAX, &pwszName, RT_ELEMENTS(wszName), &cwcName);
216 if (RT_SUCCESS(rc2))
217 {
218 static UNICODE_STRING const s_DefaultSuffix = RTNT_CONSTANT_UNISTR(L".dll");
219 WCHAR wszPath[MAX_PATH];
220 UNICODE_STRING UniStrStatic = { 0, (USHORT)sizeof(wszPath) - sizeof(WCHAR), wszPath };
221 UNICODE_STRING UniStrDynamic = { 0, 0, NULL };
222 PUNICODE_STRING pUniStrResult = NULL;
223 UNICODE_STRING UniStrName =
224 { (USHORT)(cwcName * sizeof(RTUTF16)), (USHORT)((cwcName + 1) * sizeof(RTUTF16)), wszName };
225
226 NTSTATUS rcNt = s_pfnApplyRedir(1 /*fFlags*/,
227 &UniStrName,
228 (PUNICODE_STRING)&s_DefaultSuffix,
229 &UniStrStatic,
230 &UniStrDynamic,
231 &pUniStrResult,
232 NULL /*pNewFlags*/,
233 NULL /*pcbFilename*/,
234 NULL /*pcbNeeded*/);
235 if (NT_SUCCESS(rcNt))
236 {
237 /*
238 * Check that the resolved path has similarities to the
239 * system directory.
240 *
241 * ASSUMES the windows directory is a root directory and
242 * that both System32 and are on the same level. So, we'll
243 * have 2 matching components (or more if the resolver
244 * returns a system32 path for some reason).
245 */
246 unsigned cMatchingComponents = 0;
247 size_t off = 0;
248 while (off < pUniStrResult->Length)
249 {
250 RTUTF16 wc1 = wszSysDir[off];
251 RTUTF16 wc2 = pUniStrResult->Buffer[off];
252 if (!RTPATH_IS_SLASH(wc1))
253 {
254 if (wc1 == wc2)
255 off++;
256 else if ( wc1 < 127
257 && wc2 < 127
258 && RT_C_TO_LOWER(wc1) == RT_C_TO_LOWER(wc2) )
259 off++;
260 else
261 break;
262 }
263 else if (RTPATH_IS_SLASH(wc2))
264 {
265 cMatchingComponents += off > 0;
266 do
267 off++;
268 while ( off < pUniStrResult->Length
269 && RTPATH_IS_SLASH(wszSysDir[off])
270 && RTPATH_IS_SLASH(pUniStrResult->Buffer[off]));
271 }
272 else
273 break;
274 }
275 if (cMatchingComponents >= 2)
276 {
277 pszPath = szPath;
278 rc2 = RTUtf16ToUtf8Ex(pUniStrResult->Buffer, pUniStrResult->Length / sizeof(RTUTF16),
279 &pszPath, sizeof(szPath), NULL);
280 if (RT_SUCCESS(rc2))
281 rc = VINF_SUCCESS;
282 }
283 else
284 AssertMsgFailed(("%s -> '%*.ls'\n", pszFilename, pUniStrResult->Length, pUniStrResult->Buffer));
285 RtlFreeUnicodeString(&UniStrDynamic);
286 }
287 }
288 else
289 AssertMsgFailed(("%Rrc\n", rc));
290 }
291
292 /* If the above didn't succeed, create a system32 path. */
293 if (RT_FAILURE(rc))
294 {
295 rc = RTUtf16ToUtf8Ex(wszSysDir, RTSTR_MAX, &pszPath, sizeof(szPath), NULL);
296 if (RT_SUCCESS(rc))
297 {
298 rc = RTPathAppend(szPath, sizeof(szPath), pszFilename);
299 if (pszExt && RT_SUCCESS(rc))
300 rc = RTStrCat(szPath, sizeof(szPath), pszExt);
301 }
302 }
303
304 /* Do the actual loading, if we were successful constructing a name. */
305 if (RT_SUCCESS(rc))
306 {
307 if (RTFileExists(szPath))
308 rc = RTLdrLoadEx(szPath, phLdrMod, fFlags, NULL);
309 else
310 rc = VERR_MODULE_NOT_FOUND;
311 }
312
313 return rc;
314}
315
Note: See TracBrowser for help on using the repository browser.

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