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 31const 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 58static 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*/ 172extern HMODULE PyWin_DLLhModule; 173static 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 220dl_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