VirtualBox

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

Last change on this file since 96124 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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