1*6777b538SAndroid Build Coastguard Worker // Copyright 2011 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "base/native_library.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <windows.h>
8*6777b538SAndroid Build Coastguard Worker
9*6777b538SAndroid Build Coastguard Worker #include "base/files/file_util.h"
10*6777b538SAndroid Build Coastguard Worker #include "base/metrics/histogram_macros.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/path_service.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/scoped_native_library.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/strings/strcat.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_piece.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/strings/stringprintf.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/strings/utf_string_conversions.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/threading/scoped_blocking_call.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/threading/scoped_thread_priority.h"
20*6777b538SAndroid Build Coastguard Worker
21*6777b538SAndroid Build Coastguard Worker namespace base {
22*6777b538SAndroid Build Coastguard Worker
23*6777b538SAndroid Build Coastguard Worker namespace {
24*6777b538SAndroid Build Coastguard Worker
LoadNativeLibraryHelper(const FilePath & library_path,NativeLibraryLoadError * error)25*6777b538SAndroid Build Coastguard Worker NativeLibrary LoadNativeLibraryHelper(const FilePath& library_path,
26*6777b538SAndroid Build Coastguard Worker NativeLibraryLoadError* error) {
27*6777b538SAndroid Build Coastguard Worker // LoadLibrary() opens the file off disk and acquires the LoaderLock, hence
28*6777b538SAndroid Build Coastguard Worker // must not be called from DllMain.
29*6777b538SAndroid Build Coastguard Worker ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
30*6777b538SAndroid Build Coastguard Worker
31*6777b538SAndroid Build Coastguard Worker // Mitigate the issues caused by loading DLLs on a background thread
32*6777b538SAndroid Build Coastguard Worker // (see http://crbug/973868 for context). This temporarily boosts this
33*6777b538SAndroid Build Coastguard Worker // thread's priority so that it doesn't get starved by higher priority threads
34*6777b538SAndroid Build Coastguard Worker // while it holds the LoaderLock.
35*6777b538SAndroid Build Coastguard Worker SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY_REPEATEDLY();
36*6777b538SAndroid Build Coastguard Worker
37*6777b538SAndroid Build Coastguard Worker HMODULE module_handle = nullptr;
38*6777b538SAndroid Build Coastguard Worker
39*6777b538SAndroid Build Coastguard Worker // LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR flag is needed to search the library
40*6777b538SAndroid Build Coastguard Worker // directory as the library may have dependencies on DLLs in this
41*6777b538SAndroid Build Coastguard Worker // directory.
42*6777b538SAndroid Build Coastguard Worker module_handle = ::LoadLibraryExW(
43*6777b538SAndroid Build Coastguard Worker library_path.value().c_str(), nullptr,
44*6777b538SAndroid Build Coastguard Worker LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
45*6777b538SAndroid Build Coastguard Worker // If LoadLibraryExW succeeds, log this metric and return.
46*6777b538SAndroid Build Coastguard Worker if (module_handle) {
47*6777b538SAndroid Build Coastguard Worker return module_handle;
48*6777b538SAndroid Build Coastguard Worker }
49*6777b538SAndroid Build Coastguard Worker // GetLastError() needs to be called immediately after
50*6777b538SAndroid Build Coastguard Worker // LoadLibraryExW call.
51*6777b538SAndroid Build Coastguard Worker if (error) {
52*6777b538SAndroid Build Coastguard Worker error->code = ::GetLastError();
53*6777b538SAndroid Build Coastguard Worker }
54*6777b538SAndroid Build Coastguard Worker
55*6777b538SAndroid Build Coastguard Worker // If LoadLibraryExW API/flags are unavailable or API call fails, try
56*6777b538SAndroid Build Coastguard Worker // LoadLibraryW API. From UMA, this fallback is necessary for many users.
57*6777b538SAndroid Build Coastguard Worker
58*6777b538SAndroid Build Coastguard Worker // Switch the current directory to the library directory as the library
59*6777b538SAndroid Build Coastguard Worker // may have dependencies on DLLs in this directory.
60*6777b538SAndroid Build Coastguard Worker bool restore_directory = false;
61*6777b538SAndroid Build Coastguard Worker FilePath current_directory;
62*6777b538SAndroid Build Coastguard Worker if (GetCurrentDirectory(¤t_directory)) {
63*6777b538SAndroid Build Coastguard Worker FilePath plugin_path = library_path.DirName();
64*6777b538SAndroid Build Coastguard Worker if (!plugin_path.empty()) {
65*6777b538SAndroid Build Coastguard Worker SetCurrentDirectory(plugin_path);
66*6777b538SAndroid Build Coastguard Worker restore_directory = true;
67*6777b538SAndroid Build Coastguard Worker }
68*6777b538SAndroid Build Coastguard Worker }
69*6777b538SAndroid Build Coastguard Worker module_handle = ::LoadLibraryW(library_path.value().c_str());
70*6777b538SAndroid Build Coastguard Worker
71*6777b538SAndroid Build Coastguard Worker // GetLastError() needs to be called immediately after LoadLibraryW call.
72*6777b538SAndroid Build Coastguard Worker if (!module_handle && error) {
73*6777b538SAndroid Build Coastguard Worker error->code = ::GetLastError();
74*6777b538SAndroid Build Coastguard Worker }
75*6777b538SAndroid Build Coastguard Worker
76*6777b538SAndroid Build Coastguard Worker if (restore_directory)
77*6777b538SAndroid Build Coastguard Worker SetCurrentDirectory(current_directory);
78*6777b538SAndroid Build Coastguard Worker
79*6777b538SAndroid Build Coastguard Worker return module_handle;
80*6777b538SAndroid Build Coastguard Worker }
81*6777b538SAndroid Build Coastguard Worker
LoadSystemLibraryHelper(const FilePath & library_path,NativeLibraryLoadError * error)82*6777b538SAndroid Build Coastguard Worker NativeLibrary LoadSystemLibraryHelper(const FilePath& library_path,
83*6777b538SAndroid Build Coastguard Worker NativeLibraryLoadError* error) {
84*6777b538SAndroid Build Coastguard Worker // GetModuleHandleEx and subsequently LoadLibraryEx acquire the LoaderLock,
85*6777b538SAndroid Build Coastguard Worker // hence must not be called from Dllmain.
86*6777b538SAndroid Build Coastguard Worker ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
87*6777b538SAndroid Build Coastguard Worker NativeLibrary module;
88*6777b538SAndroid Build Coastguard Worker BOOL module_found =
89*6777b538SAndroid Build Coastguard Worker ::GetModuleHandleExW(0, library_path.value().c_str(), &module);
90*6777b538SAndroid Build Coastguard Worker if (!module_found) {
91*6777b538SAndroid Build Coastguard Worker module = ::LoadLibraryExW(library_path.value().c_str(), nullptr,
92*6777b538SAndroid Build Coastguard Worker LOAD_LIBRARY_SEARCH_SYSTEM32);
93*6777b538SAndroid Build Coastguard Worker
94*6777b538SAndroid Build Coastguard Worker if (!module && error)
95*6777b538SAndroid Build Coastguard Worker error->code = ::GetLastError();
96*6777b538SAndroid Build Coastguard Worker }
97*6777b538SAndroid Build Coastguard Worker
98*6777b538SAndroid Build Coastguard Worker return module;
99*6777b538SAndroid Build Coastguard Worker }
100*6777b538SAndroid Build Coastguard Worker
GetSystemLibraryName(FilePath::StringPieceType name)101*6777b538SAndroid Build Coastguard Worker FilePath GetSystemLibraryName(FilePath::StringPieceType name) {
102*6777b538SAndroid Build Coastguard Worker FilePath library_path;
103*6777b538SAndroid Build Coastguard Worker // Use an absolute path to load the DLL to avoid DLL preloading attacks.
104*6777b538SAndroid Build Coastguard Worker if (PathService::Get(DIR_SYSTEM, &library_path))
105*6777b538SAndroid Build Coastguard Worker library_path = library_path.Append(name);
106*6777b538SAndroid Build Coastguard Worker return library_path;
107*6777b538SAndroid Build Coastguard Worker }
108*6777b538SAndroid Build Coastguard Worker
109*6777b538SAndroid Build Coastguard Worker } // namespace
110*6777b538SAndroid Build Coastguard Worker
ToString() const111*6777b538SAndroid Build Coastguard Worker std::string NativeLibraryLoadError::ToString() const {
112*6777b538SAndroid Build Coastguard Worker return StringPrintf("%lu", code);
113*6777b538SAndroid Build Coastguard Worker }
114*6777b538SAndroid Build Coastguard Worker
LoadNativeLibraryWithOptions(const FilePath & library_path,const NativeLibraryOptions & options,NativeLibraryLoadError * error)115*6777b538SAndroid Build Coastguard Worker NativeLibrary LoadNativeLibraryWithOptions(const FilePath& library_path,
116*6777b538SAndroid Build Coastguard Worker const NativeLibraryOptions& options,
117*6777b538SAndroid Build Coastguard Worker NativeLibraryLoadError* error) {
118*6777b538SAndroid Build Coastguard Worker return LoadNativeLibraryHelper(library_path, error);
119*6777b538SAndroid Build Coastguard Worker }
120*6777b538SAndroid Build Coastguard Worker
UnloadNativeLibrary(NativeLibrary library)121*6777b538SAndroid Build Coastguard Worker void UnloadNativeLibrary(NativeLibrary library) {
122*6777b538SAndroid Build Coastguard Worker FreeLibrary(library);
123*6777b538SAndroid Build Coastguard Worker }
124*6777b538SAndroid Build Coastguard Worker
GetFunctionPointerFromNativeLibrary(NativeLibrary library,const char * name)125*6777b538SAndroid Build Coastguard Worker void* GetFunctionPointerFromNativeLibrary(NativeLibrary library,
126*6777b538SAndroid Build Coastguard Worker const char* name) {
127*6777b538SAndroid Build Coastguard Worker return reinterpret_cast<void*>(GetProcAddress(library, name));
128*6777b538SAndroid Build Coastguard Worker }
129*6777b538SAndroid Build Coastguard Worker
GetNativeLibraryName(StringPiece name)130*6777b538SAndroid Build Coastguard Worker std::string GetNativeLibraryName(StringPiece name) {
131*6777b538SAndroid Build Coastguard Worker DCHECK(IsStringASCII(name));
132*6777b538SAndroid Build Coastguard Worker return StrCat({name, ".dll"});
133*6777b538SAndroid Build Coastguard Worker }
134*6777b538SAndroid Build Coastguard Worker
GetLoadableModuleName(StringPiece name)135*6777b538SAndroid Build Coastguard Worker std::string GetLoadableModuleName(StringPiece name) {
136*6777b538SAndroid Build Coastguard Worker return GetNativeLibraryName(name);
137*6777b538SAndroid Build Coastguard Worker }
138*6777b538SAndroid Build Coastguard Worker
LoadSystemLibrary(FilePath::StringPieceType name,NativeLibraryLoadError * error)139*6777b538SAndroid Build Coastguard Worker NativeLibrary LoadSystemLibrary(FilePath::StringPieceType name,
140*6777b538SAndroid Build Coastguard Worker NativeLibraryLoadError* error) {
141*6777b538SAndroid Build Coastguard Worker FilePath library_path = GetSystemLibraryName(name);
142*6777b538SAndroid Build Coastguard Worker if (library_path.empty()) {
143*6777b538SAndroid Build Coastguard Worker if (error)
144*6777b538SAndroid Build Coastguard Worker error->code = ERROR_NOT_FOUND;
145*6777b538SAndroid Build Coastguard Worker return nullptr;
146*6777b538SAndroid Build Coastguard Worker }
147*6777b538SAndroid Build Coastguard Worker return LoadSystemLibraryHelper(library_path, error);
148*6777b538SAndroid Build Coastguard Worker }
149*6777b538SAndroid Build Coastguard Worker
PinSystemLibrary(FilePath::StringPieceType name,NativeLibraryLoadError * error)150*6777b538SAndroid Build Coastguard Worker NativeLibrary PinSystemLibrary(FilePath::StringPieceType name,
151*6777b538SAndroid Build Coastguard Worker NativeLibraryLoadError* error) {
152*6777b538SAndroid Build Coastguard Worker FilePath library_path = GetSystemLibraryName(name);
153*6777b538SAndroid Build Coastguard Worker if (library_path.empty()) {
154*6777b538SAndroid Build Coastguard Worker if (error)
155*6777b538SAndroid Build Coastguard Worker error->code = ERROR_NOT_FOUND;
156*6777b538SAndroid Build Coastguard Worker return nullptr;
157*6777b538SAndroid Build Coastguard Worker }
158*6777b538SAndroid Build Coastguard Worker
159*6777b538SAndroid Build Coastguard Worker // GetModuleHandleEx acquires the LoaderLock, hence must not be called from
160*6777b538SAndroid Build Coastguard Worker // Dllmain.
161*6777b538SAndroid Build Coastguard Worker ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
162*6777b538SAndroid Build Coastguard Worker ScopedNativeLibrary module;
163*6777b538SAndroid Build Coastguard Worker if (::GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_PIN,
164*6777b538SAndroid Build Coastguard Worker library_path.value().c_str(),
165*6777b538SAndroid Build Coastguard Worker ScopedNativeLibrary::Receiver(module).get())) {
166*6777b538SAndroid Build Coastguard Worker return module.release();
167*6777b538SAndroid Build Coastguard Worker }
168*6777b538SAndroid Build Coastguard Worker
169*6777b538SAndroid Build Coastguard Worker // Load and pin the library since it wasn't already loaded.
170*6777b538SAndroid Build Coastguard Worker module = ScopedNativeLibrary(LoadSystemLibraryHelper(library_path, error));
171*6777b538SAndroid Build Coastguard Worker if (!module.is_valid())
172*6777b538SAndroid Build Coastguard Worker return nullptr;
173*6777b538SAndroid Build Coastguard Worker
174*6777b538SAndroid Build Coastguard Worker ScopedNativeLibrary temp;
175*6777b538SAndroid Build Coastguard Worker if (::GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_PIN,
176*6777b538SAndroid Build Coastguard Worker library_path.value().c_str(),
177*6777b538SAndroid Build Coastguard Worker ScopedNativeLibrary::Receiver(temp).get())) {
178*6777b538SAndroid Build Coastguard Worker return module.release();
179*6777b538SAndroid Build Coastguard Worker }
180*6777b538SAndroid Build Coastguard Worker
181*6777b538SAndroid Build Coastguard Worker if (error)
182*6777b538SAndroid Build Coastguard Worker error->code = ::GetLastError();
183*6777b538SAndroid Build Coastguard Worker // Return nullptr since we failed to pin the module.
184*6777b538SAndroid Build Coastguard Worker return nullptr;
185*6777b538SAndroid Build Coastguard Worker }
186*6777b538SAndroid Build Coastguard Worker
187*6777b538SAndroid Build Coastguard Worker } // namespace base
188