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