1
2 /* Support for dynamic loading of extension modules */
3
4 #include "Python.h"
5 #include "pycore_fileutils.h" // _Py_add_relfile()
6 #include "pycore_pystate.h" // _PyInterpreterState_GET()
7
8 #include "pycore_importdl.h" // dl_funcptr
9 #include "patchlevel.h" // PY_MAJOR_VERSION
10 #include <windows.h>
11
12 const char *_PyImport_DynLoadFiletab[] = {
13 PYD_TAGGED_SUFFIX,
14 PYD_UNTAGGED_SUFFIX,
15 NULL
16 };
17
18 /* Function to return the name of the "python" DLL that the supplied module
19 directly imports. Looks through the list of imported modules and
20 returns the first entry that starts with "python" (case sensitive) and
21 is followed by nothing but numbers until the separator (period).
22
23 Returns a pointer to the import name, or NULL if no matching name was
24 located.
25
26 This function parses through the PE header for the module as loaded in
27 memory by the system loader. The PE header is accessed as documented by
28 Microsoft in the MSDN PE and COFF specification (2/99), and handles
29 both PE32 and PE32+. It only worries about the direct import table and
30 not the delay load import table since it's unlikely an extension is
31 going to be delay loading Python (after all, it's already loaded).
32
33 If any magic values are not found (e.g., the PE header or optional
34 header magic), then this function simply returns NULL. */
35
36 #define DWORD_AT(mem) (*(DWORD *)(mem))
37 #define WORD_AT(mem) (*(WORD *)(mem))
38
GetPythonImport(HINSTANCE hModule)39 static char *GetPythonImport (HINSTANCE hModule)
40 {
41 unsigned char *dllbase, *import_data, *import_name;
42 DWORD pe_offset, opt_offset;
43 WORD opt_magic;
44 int num_dict_off, import_off;
45
46 /* Safety check input */
47 if (hModule == NULL) {
48 return NULL;
49 }
50
51 /* Module instance is also the base load address. First portion of
52 memory is the MS-DOS loader, which holds the offset to the PE
53 header (from the load base) at 0x3C */
54 dllbase = (unsigned char *)hModule;
55 pe_offset = DWORD_AT(dllbase + 0x3C);
56
57 /* The PE signature must be "PE\0\0" */
58 if (memcmp(dllbase+pe_offset,"PE\0\0",4)) {
59 return NULL;
60 }
61
62 /* Following the PE signature is the standard COFF header (20
63 bytes) and then the optional header. The optional header starts
64 with a magic value of 0x10B for PE32 or 0x20B for PE32+ (PE32+
65 uses 64-bits for some fields). It might also be 0x107 for a ROM
66 image, but we don't process that here.
67
68 The optional header ends with a data dictionary that directly
69 points to certain types of data, among them the import entries
70 (in the second table entry). Based on the header type, we
71 determine offsets for the data dictionary count and the entry
72 within the dictionary pointing to the imports. */
73
74 opt_offset = pe_offset + 4 + 20;
75 opt_magic = WORD_AT(dllbase+opt_offset);
76 if (opt_magic == 0x10B) {
77 /* PE32 */
78 num_dict_off = 92;
79 import_off = 104;
80 } else if (opt_magic == 0x20B) {
81 /* PE32+ */
82 num_dict_off = 108;
83 import_off = 120;
84 } else {
85 /* Unsupported */
86 return NULL;
87 }
88
89 /* Now if an import table exists, offset to it and walk the list of
90 imports. The import table is an array (ending when an entry has
91 empty values) of structures (20 bytes each), which contains (at
92 offset 12) a relative address (to the module base) at which a
93 string constant holding the import name is located. */
94
95 if (DWORD_AT(dllbase + opt_offset + num_dict_off) >= 2) {
96 /* We have at least 2 tables - the import table is the second
97 one. But still it may be that the table size is zero */
98 if (0 == DWORD_AT(dllbase + opt_offset + import_off + sizeof(DWORD)))
99 return NULL;
100 import_data = dllbase + DWORD_AT(dllbase +
101 opt_offset +
102 import_off);
103 while (DWORD_AT(import_data)) {
104 import_name = dllbase + DWORD_AT(import_data+12);
105 if (strlen(import_name) >= 6 &&
106 !strncmp(import_name,"python",6)) {
107 char *pch;
108
109 /* Don't claim that python3.dll is a Python DLL. */
110 #ifdef _DEBUG
111 if (strcmp(import_name, "python3_d.dll") == 0) {
112 #else
113 if (strcmp(import_name, "python3.dll") == 0) {
114 #endif
115 import_data += 20;
116 continue;
117 }
118
119 /* Ensure python prefix is followed only
120 by numbers to the end of the basename */
121 pch = import_name + 6;
122 #ifdef _DEBUG
123 while (*pch && pch[0] != '_' && pch[1] != 'd' && pch[2] != '.') {
124 #else
125 while (*pch && *pch != '.') {
126 #endif
127 if (*pch >= '0' && *pch <= '9') {
128 pch++;
129 } else {
130 pch = NULL;
131 break;
132 }
133 }
134
135 if (pch) {
136 /* Found it - return the name */
137 return import_name;
138 }
139 }
140 import_data += 20;
141 }
142 }
143
144 return NULL;
145 }
146
147 #ifdef Py_ENABLE_SHARED
148 /* Load python3.dll before loading any extension module that might refer
149 to it. That way, we can be sure that always the python3.dll corresponding
150 to this python DLL is loaded, not a python3.dll that might be on the path
151 by chance.
152 Return whether the DLL was found.
153 */
154 extern HMODULE PyWin_DLLhModule;
155 static int
156 _Py_CheckPython3(void)
157 {
158 static int python3_checked = 0;
159 static HANDLE hPython3;
160 #define MAXPATHLEN 512
161 wchar_t py3path[MAXPATHLEN+1];
162 if (python3_checked) {
163 return hPython3 != NULL;
164 }
165 python3_checked = 1;
166
167 /* If there is a python3.dll next to the python3y.dll,
168 use that DLL */
169 if (PyWin_DLLhModule && GetModuleFileNameW(PyWin_DLLhModule, py3path, MAXPATHLEN)) {
170 wchar_t *p = wcsrchr(py3path, L'\\');
171 if (p) {
172 wcscpy(p + 1, PY3_DLLNAME);
173 hPython3 = LoadLibraryExW(py3path, NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
174 if (hPython3 != NULL) {
175 return 1;
176 }
177 }
178 }
179
180 /* If we can locate python3.dll in our application dir,
181 use that DLL */
182 hPython3 = LoadLibraryExW(PY3_DLLNAME, NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR);
183 if (hPython3 != NULL) {
184 return 1;
185 }
186
187 /* For back-compat, also search {sys.prefix}\DLLs, though
188 that has not been a normal install layout for a while */
189 PyInterpreterState *interp = _PyInterpreterState_GET();
190 PyConfig *config = (PyConfig*)_PyInterpreterState_GetConfig(interp);
191 assert(config->prefix);
192 if (config->prefix) {
193 wcscpy_s(py3path, MAXPATHLEN, config->prefix);
194 if (py3path[0] && _Py_add_relfile(py3path, L"DLLs\\" PY3_DLLNAME, MAXPATHLEN) >= 0) {
195 hPython3 = LoadLibraryExW(py3path, NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
196 }
197 }
198 return hPython3 != NULL;
199 #undef MAXPATHLEN
200 }
201 #endif /* Py_ENABLE_SHARED */
202
203 dl_funcptr _PyImport_FindSharedFuncptrWindows(const char *prefix,
204 const char *shortname,
205 PyObject *pathname, FILE *fp)
206 {
207 dl_funcptr p;
208 char funcname[258], *import_python;
209
210 #ifdef Py_ENABLE_SHARED
211 _Py_CheckPython3();
212 #endif /* Py_ENABLE_SHARED */
213
214 wchar_t *wpathname = PyUnicode_AsWideCharString(pathname, NULL);
215 if (wpathname == NULL)
216 return NULL;
217
218 PyOS_snprintf(funcname, sizeof(funcname), "%.20s_%.200s", prefix, shortname);
219
220 {
221 HINSTANCE hDLL = NULL;
222 #ifdef MS_WINDOWS_DESKTOP
223 unsigned int old_mode;
224
225 /* Don't display a message box when Python can't load a DLL */
226 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
227 #endif
228
229 /* bpo-36085: We use LoadLibraryEx with restricted search paths
230 to avoid DLL preloading attacks and enable use of the
231 AddDllDirectory function. We add SEARCH_DLL_LOAD_DIR to
232 ensure DLLs adjacent to the PYD are preferred. */
233 Py_BEGIN_ALLOW_THREADS
234 hDLL = LoadLibraryExW(wpathname, NULL,
235 LOAD_LIBRARY_SEARCH_DEFAULT_DIRS |
236 LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR);
237 Py_END_ALLOW_THREADS
238 PyMem_Free(wpathname);
239
240 #ifdef MS_WINDOWS_DESKTOP
241 /* restore old error mode settings */
242 SetErrorMode(old_mode);
243 #endif
244
245 if (hDLL==NULL){
246 PyObject *message;
247 unsigned int errorCode;
248
249 /* Get an error string from Win32 error code */
250 wchar_t theInfo[256]; /* Pointer to error text
251 from system */
252 int theLength; /* Length of error text */
253
254 errorCode = GetLastError();
255
256 theLength = FormatMessageW(
257 FORMAT_MESSAGE_FROM_SYSTEM |
258 FORMAT_MESSAGE_IGNORE_INSERTS, /* flags */
259 NULL, /* message source */
260 errorCode, /* the message (error) ID */
261 MAKELANGID(LANG_NEUTRAL,
262 SUBLANG_DEFAULT),
263 /* Default language */
264 theInfo, /* the buffer */
265 sizeof(theInfo) / sizeof(wchar_t), /* size in wchars */
266 NULL); /* no additional format args. */
267
268 /* Problem: could not get the error message.
269 This should not happen if called correctly. */
270 if (theLength == 0) {
271 message = PyUnicode_FromFormat(
272 "DLL load failed with error code %u while importing %s",
273 errorCode, shortname);
274 } else {
275 /* For some reason a \r\n
276 is appended to the text */
277 if (theLength >= 2 &&
278 theInfo[theLength-2] == '\r' &&
279 theInfo[theLength-1] == '\n') {
280 theLength -= 2;
281 theInfo[theLength] = '\0';
282 }
283 message = PyUnicode_FromFormat(
284 "DLL load failed while importing %s: ", shortname);
285
286 PyUnicode_AppendAndDel(&message,
287 PyUnicode_FromWideChar(
288 theInfo,
289 theLength));
290 }
291 if (message != NULL) {
292 PyObject *shortname_obj = PyUnicode_FromString(shortname);
293 PyErr_SetImportError(message, shortname_obj, pathname);
294 Py_XDECREF(shortname_obj);
295 Py_DECREF(message);
296 }
297 return NULL;
298 } else {
299 char buffer[256];
300
301 PyOS_snprintf(buffer, sizeof(buffer),
302 #ifdef _DEBUG
303 "python%d%d_d.dll",
304 #else
305 "python%d%d.dll",
306 #endif
307 PY_MAJOR_VERSION,PY_MINOR_VERSION);
308 import_python = GetPythonImport(hDLL);
309
310 if (import_python &&
311 _stricmp(buffer,import_python)) {
312 PyErr_Format(PyExc_ImportError,
313 "Module use of %.150s conflicts "
314 "with this version of Python.",
315 import_python);
316 Py_BEGIN_ALLOW_THREADS
317 FreeLibrary(hDLL);
318 Py_END_ALLOW_THREADS
319 return NULL;
320 }
321 }
322 Py_BEGIN_ALLOW_THREADS
323 p = GetProcAddress(hDLL, funcname);
324 Py_END_ALLOW_THREADS
325 }
326
327 return p;
328 }
329