blob: 6124f607fc84cc9093cd4a8cc1ab340b82a5e959 [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2011 The Chromium Authors
[email protected]f38e25f2009-04-21 00:56:072// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/native_library.h"
6
7#include <windows.h>
8
Helmut Januschka1dce9dc2024-06-11 13:05:359#include <string_view>
10
[email protected]e3177dd52014-08-13 20:22:1411#include "base/files/file_util.h"
chengx5946c922017-03-16 05:49:2112#include "base/metrics/histogram_macros.h"
Cliff Smolinskyf395bef2019-04-12 23:45:4413#include "base/path_service.h"
14#include "base/scoped_native_library.h"
Jan Wilken Dörrie5db50ac2021-02-15 11:43:1615#include "base/strings/strcat.h"
thestig02c965b2016-06-14 18:52:2316#include "base/strings/string_util.h"
[email protected]f4e911452014-03-20 06:07:2617#include "base/strings/stringprintf.h"
[email protected]a4ea1f12013-06-07 18:37:0718#include "base/strings/utf_string_conversions.h"
Etienne Pierre-Doray3879b052018-09-17 14:17:2219#include "base/threading/scoped_blocking_call.h"
Anthony Vallee-Dubois3aafcf22022-02-10 16:52:0420#include "base/threading/scoped_thread_priority.h"
[email protected]f38e25f2009-04-21 00:56:0721
22namespace base {
23
[email protected]0f998442014-03-25 01:59:0924namespace {
Cliff Smolinskyf395bef2019-04-12 23:45:4425
[email protected]3e246222010-11-19 23:33:1326NativeLibrary LoadNativeLibraryHelper(const FilePath& library_path,
[email protected]0f998442014-03-25 01:59:0927 NativeLibraryLoadError* error) {
Cliff Smolinskyf395bef2019-04-12 23:45:4428 // LoadLibrary() opens the file off disk and acquires the LoaderLock, hence
29 // must not be called from DllMain.
Etienne Bergeron436d42212019-02-26 17:15:1230 ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
[email protected]be130682010-11-12 21:53:1631
Anthony Vallee-Dubois3aafcf22022-02-10 16:52:0432 // Mitigate the issues caused by loading DLLs on a background thread
33 // (see http://crbug/973868 for context). This temporarily boosts this
34 // thread's priority so that it doesn't get starved by higher priority threads
35 // while it holds the LoaderLock.
36 SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY_REPEATEDLY();
37
David Bienvenue2791612023-02-03 15:56:4538 HMODULE module_handle = nullptr;
chengx5946c922017-03-16 05:49:2139
David Bienvenue2791612023-02-03 15:56:4540 // LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR flag is needed to search the library
41 // directory as the library may have dependencies on DLLs in this
42 // directory.
43 module_handle = ::LoadLibraryExW(
44 library_path.value().c_str(), nullptr,
45 LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
46 // If LoadLibraryExW succeeds, log this metric and return.
47 if (module_handle) {
David Bienvenue2791612023-02-03 15:56:4548 return module_handle;
49 }
50 // GetLastError() needs to be called immediately after
51 // LoadLibraryExW call.
52 if (error) {
53 error->code = ::GetLastError();
chengx5946c922017-03-16 05:49:2154 }
55
56 // If LoadLibraryExW API/flags are unavailable or API call fails, try
Xi Cheng2740c2c2018-11-20 22:25:2257 // LoadLibraryW API. From UMA, this fallback is necessary for many users.
chengx5946c922017-03-16 05:49:2158
[email protected]f38e25f2009-04-21 00:56:0759 // Switch the current directory to the library directory as the library
60 // may have dependencies on DLLs in this directory.
61 bool restore_directory = false;
[email protected]188505282009-09-16 16:31:2862 FilePath current_directory;
[email protected]37b3c1992014-03-11 20:59:0263 if (GetCurrentDirectory(&current_directory)) {
[email protected]f38e25f2009-04-21 00:56:0764 FilePath plugin_path = library_path.DirName();
[email protected]188505282009-09-16 16:31:2865 if (!plugin_path.empty()) {
[email protected]37b3c1992014-03-11 20:59:0266 SetCurrentDirectory(plugin_path);
[email protected]f38e25f2009-04-21 00:56:0767 restore_directory = true;
68 }
69 }
David Bienvenue2791612023-02-03 15:56:4570 module_handle = ::LoadLibraryW(library_path.value().c_str());
chengx5946c922017-03-16 05:49:2171
72 // GetLastError() needs to be called immediately after LoadLibraryW call.
David Bienvenue2791612023-02-03 15:56:4573 if (!module_handle && error) {
Cliff Smolinskyc5c52102019-05-03 20:51:5474 error->code = ::GetLastError();
David Bienvenue2791612023-02-03 15:56:4575 }
[email protected]f4e911452014-03-20 06:07:2676
Peter Kasting134ef9af2024-12-28 02:30:0977 if (restore_directory) {
[email protected]37b3c1992014-03-11 20:59:0278 SetCurrentDirectory(current_directory);
Peter Kasting134ef9af2024-12-28 02:30:0979 }
[email protected]f38e25f2009-04-21 00:56:0780
David Bienvenue2791612023-02-03 15:56:4581 return module_handle;
[email protected]f38e25f2009-04-21 00:56:0782}
Cliff Smolinskyf395bef2019-04-12 23:45:4483
84NativeLibrary LoadSystemLibraryHelper(const FilePath& library_path,
85 NativeLibraryLoadError* error) {
Cliff Smolinskyc5c52102019-05-03 20:51:5486 // GetModuleHandleEx and subsequently LoadLibraryEx acquire the LoaderLock,
87 // hence must not be called from Dllmain.
88 ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
Cliff Smolinskyf395bef2019-04-12 23:45:4489 NativeLibrary module;
90 BOOL module_found =
Jan Wilken Dörrieb630aca2019-12-04 10:59:1191 ::GetModuleHandleExW(0, library_path.value().c_str(), &module);
Cliff Smolinskyf395bef2019-04-12 23:45:4492 if (!module_found) {
David Bienvenue2791612023-02-03 15:56:4593 module = ::LoadLibraryExW(library_path.value().c_str(), nullptr,
94 LOAD_LIBRARY_SEARCH_SYSTEM32);
Cliff Smolinskyf395bef2019-04-12 23:45:4495
Peter Kasting134ef9af2024-12-28 02:30:0996 if (!module && error) {
Cliff Smolinskyf395bef2019-04-12 23:45:4497 error->code = ::GetLastError();
Peter Kasting134ef9af2024-12-28 02:30:0998 }
Cliff Smolinskyf395bef2019-04-12 23:45:4499 }
100
101 return module;
102}
103
Lei Zhangb88b59b92025-02-05 22:46:47104FilePath GetSystemLibraryName(FilePath::StringViewType name) {
Cliff Smolinskyf395bef2019-04-12 23:45:44105 FilePath library_path;
106 // Use an absolute path to load the DLL to avoid DLL preloading attacks.
Peter Kasting134ef9af2024-12-28 02:30:09107 if (PathService::Get(DIR_SYSTEM, &library_path)) {
Lei Zhang4c836692019-09-27 02:14:55108 library_path = library_path.Append(name);
Peter Kasting134ef9af2024-12-28 02:30:09109 }
Lei Zhang4c836692019-09-27 02:14:55110 return library_path;
Cliff Smolinskyf395bef2019-04-12 23:45:44111}
112
[email protected]0f998442014-03-25 01:59:09113} // namespace
114
115std::string NativeLibraryLoadError::ToString() const {
Bruce Dawson19175842017-08-02 17:00:45116 return StringPrintf("%lu", code);
[email protected]0f998442014-03-25 01:59:09117}
118
rockot596a0dd2016-08-26 00:57:51119NativeLibrary LoadNativeLibraryWithOptions(const FilePath& library_path,
120 const NativeLibraryOptions& options,
121 NativeLibraryLoadError* error) {
chengx5946c922017-03-16 05:49:21122 return LoadNativeLibraryHelper(library_path, error);
[email protected]3e246222010-11-19 23:33:13123}
124
[email protected]f38e25f2009-04-21 00:56:07125void UnloadNativeLibrary(NativeLibrary library) {
126 FreeLibrary(library);
127}
128
[email protected]f38e25f2009-04-21 00:56:07129void* GetFunctionPointerFromNativeLibrary(NativeLibrary library,
David Benjamina9420072023-06-13 14:38:36130 const char* name) {
131 return reinterpret_cast<void*>(GetProcAddress(library, name));
[email protected]f38e25f2009-04-21 00:56:07132}
133
Helmut Januschka1dce9dc2024-06-11 13:05:35134std::string GetNativeLibraryName(std::string_view name) {
thestig02c965b2016-06-14 18:52:23135 DCHECK(IsStringASCII(name));
Jan Wilken Dörrie5db50ac2021-02-15 11:43:16136 return StrCat({name, ".dll"});
[email protected]108c2a12009-06-05 22:18:09137}
138
Helmut Januschka1dce9dc2024-06-11 13:05:35139std::string GetLoadableModuleName(std::string_view name) {
Xiaohan Wangd807ec32018-04-03 01:31:44140 return GetNativeLibraryName(name);
141}
142
Lei Zhangb88b59b92025-02-05 22:46:47143NativeLibrary LoadSystemLibrary(FilePath::StringViewType name,
Cliff Smolinskyf395bef2019-04-12 23:45:44144 NativeLibraryLoadError* error) {
Lei Zhang4c836692019-09-27 02:14:55145 FilePath library_path = GetSystemLibraryName(name);
146 if (library_path.empty()) {
Peter Kasting134ef9af2024-12-28 02:30:09147 if (error) {
Lei Zhang4c836692019-09-27 02:14:55148 error->code = ERROR_NOT_FOUND;
Peter Kasting134ef9af2024-12-28 02:30:09149 }
Lei Zhang4c836692019-09-27 02:14:55150 return nullptr;
151 }
152 return LoadSystemLibraryHelper(library_path, error);
Cliff Smolinskyf395bef2019-04-12 23:45:44153}
154
Lei Zhangb88b59b92025-02-05 22:46:47155NativeLibrary PinSystemLibrary(FilePath::StringViewType name,
Cliff Smolinskyc5c52102019-05-03 20:51:54156 NativeLibraryLoadError* error) {
Lei Zhang4c836692019-09-27 02:14:55157 FilePath library_path = GetSystemLibraryName(name);
158 if (library_path.empty()) {
Peter Kasting134ef9af2024-12-28 02:30:09159 if (error) {
Cliff Smolinskyc5c52102019-05-03 20:51:54160 error->code = ERROR_NOT_FOUND;
Peter Kasting134ef9af2024-12-28 02:30:09161 }
Cliff Smolinskyc5c52102019-05-03 20:51:54162 return nullptr;
163 }
164
165 // GetModuleHandleEx acquires the LoaderLock, hence must not be called from
166 // Dllmain.
167 ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
168 ScopedNativeLibrary module;
Lei Zhang4c836692019-09-27 02:14:55169 if (::GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_PIN,
Jan Wilken Dörrieb630aca2019-12-04 10:59:11170 library_path.value().c_str(),
Lei Zhang4c836692019-09-27 02:14:55171 ScopedNativeLibrary::Receiver(module).get())) {
172 return module.release();
Cliff Smolinskyc5c52102019-05-03 20:51:54173 }
Lei Zhang4c836692019-09-27 02:14:55174
175 // Load and pin the library since it wasn't already loaded.
176 module = ScopedNativeLibrary(LoadSystemLibraryHelper(library_path, error));
Peter Kasting134ef9af2024-12-28 02:30:09177 if (!module.is_valid()) {
Lei Zhang4c836692019-09-27 02:14:55178 return nullptr;
Peter Kasting134ef9af2024-12-28 02:30:09179 }
Lei Zhang4c836692019-09-27 02:14:55180
181 ScopedNativeLibrary temp;
182 if (::GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_PIN,
Jan Wilken Dörrieb630aca2019-12-04 10:59:11183 library_path.value().c_str(),
Lei Zhang4c836692019-09-27 02:14:55184 ScopedNativeLibrary::Receiver(temp).get())) {
185 return module.release();
186 }
187
Peter Kasting134ef9af2024-12-28 02:30:09188 if (error) {
Lei Zhang4c836692019-09-27 02:14:55189 error->code = ::GetLastError();
Peter Kasting134ef9af2024-12-28 02:30:09190 }
Lei Zhang4c836692019-09-27 02:14:55191 // Return nullptr since we failed to pin the module.
192 return nullptr;
Cliff Smolinskyc5c52102019-05-03 20:51:54193}
194
[email protected]f38e25f2009-04-21 00:56:07195} // namespace base