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