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