From dcbaa1b49cd9062fb9ba2b9d49555ac6cd8c60b5 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Mon, 6 Jul 2020 17:32:00 +0100 Subject: bpo-29778: Ensure python3.dll is loaded from correct locations when Python is embedded (GH-21297) Also enables using debug build of `python3_d.dll` Reference: CVE-2020-15523 --- PC/getpathp.c | 150 ++++++++++++++++++++++++++++------------------------------ 1 file changed, 73 insertions(+), 77 deletions(-) (limited to 'PC') diff --git a/PC/getpathp.c b/PC/getpathp.c index fd5cfa7e1a8..0939c5fa984 100644 --- a/PC/getpathp.c +++ b/PC/getpathp.c @@ -131,8 +131,6 @@ typedef struct { wchar_t *machine_path; /* from HKEY_LOCAL_MACHINE */ wchar_t *user_path; /* from HKEY_CURRENT_USER */ - wchar_t *dll_path; - const wchar_t *pythonpath_env; } PyCalculatePath; @@ -168,27 +166,37 @@ reduce(wchar_t *dir) static int change_ext(wchar_t *dest, const wchar_t *src, const wchar_t *ext) { - size_t src_len = wcsnlen_s(src, MAXPATHLEN+1); - size_t i = src_len; - if (i >= MAXPATHLEN+1) { - Py_FatalError("buffer overflow in getpathp.c's reduce()"); - } + if (src && src != dest) { + size_t src_len = wcsnlen_s(src, MAXPATHLEN+1); + size_t i = src_len; + if (i >= MAXPATHLEN+1) { + Py_FatalError("buffer overflow in getpathp.c's reduce()"); + } - while (i > 0 && src[i] != '.' && !is_sep(src[i])) - --i; + while (i > 0 && src[i] != '.' && !is_sep(src[i])) + --i; - if (i == 0) { - dest[0] = '\0'; - return -1; - } + if (i == 0) { + dest[0] = '\0'; + return -1; + } + + if (is_sep(src[i])) { + i = src_len; + } - if (is_sep(src[i])) { - i = src_len; + if (wcsncpy_s(dest, MAXPATHLEN+1, src, i)) { + dest[0] = '\0'; + return -1; + } + } else { + wchar_t *s = wcsrchr(dest, L'.'); + if (s) { + s[0] = '\0'; + } } - if (wcsncpy_s(dest, MAXPATHLEN+1, src, i) || - wcscat_s(dest, MAXPATHLEN+1, ext)) - { + if (wcscat_s(dest, MAXPATHLEN+1, ext)) { dest[0] = '\0'; return -1; } @@ -297,6 +305,19 @@ search_for_prefix(wchar_t *prefix, const wchar_t *argv0_path, const wchar_t *lan } +static int +get_dllpath(wchar_t *dllpath) +{ +#ifdef Py_ENABLE_SHARED + extern HANDLE PyWin_DLLhModule; + if (PyWin_DLLhModule && GetModuleFileNameW(PyWin_DLLhModule, dllpath, MAXPATHLEN)) { + return 0; + } +#endif + return -1; +} + + #ifdef Py_ENABLE_SHARED /* a string loaded from the DLL at startup.*/ @@ -468,27 +489,6 @@ getpythonregpath(HKEY keyBase, int skipcore) #endif /* Py_ENABLE_SHARED */ -wchar_t* -_Py_GetDLLPath(void) -{ - wchar_t dll_path[MAXPATHLEN+1]; - memset(dll_path, 0, sizeof(dll_path)); - -#ifdef Py_ENABLE_SHARED - extern HANDLE PyWin_DLLhModule; - if (PyWin_DLLhModule) { - if (!GetModuleFileNameW(PyWin_DLLhModule, dll_path, MAXPATHLEN)) { - dll_path[0] = 0; - } - } -#else - dll_path[0] = 0; -#endif - - return _PyMem_RawWcsdup(dll_path); -} - - static PyStatus get_program_full_path(_PyPathConfig *pathconfig) { @@ -669,19 +669,17 @@ static int get_pth_filename(PyCalculatePath *calculate, wchar_t *filename, const _PyPathConfig *pathconfig) { - if (calculate->dll_path[0]) { - if (!change_ext(filename, calculate->dll_path, L"._pth") && - exists(filename)) - { - return 1; - } + if (get_dllpath(filename) && + !change_ext(filename, filename, L"._pth") && + exists(filename)) + { + return 1; } - if (pathconfig->program_full_path[0]) { - if (!change_ext(filename, pathconfig->program_full_path, L"._pth") && - exists(filename)) - { - return 1; - } + if (pathconfig->program_full_path[0] && + !change_ext(filename, pathconfig->program_full_path, L"._pth") && + exists(filename)) + { + return 1; } return 0; } @@ -994,9 +992,12 @@ calculate_path(PyCalculatePath *calculate, _PyPathConfig *pathconfig) wchar_t zip_path[MAXPATHLEN+1]; memset(zip_path, 0, sizeof(zip_path)); - change_ext(zip_path, - calculate->dll_path[0] ? calculate->dll_path : pathconfig->program_full_path, - L".zip"); + if (get_dllpath(zip_path) || change_ext(zip_path, zip_path, L".zip")) + { + if (change_ext(zip_path, pathconfig->program_full_path, L".zip")) { + zip_path[0] = L'\0'; + } + } calculate_home_prefix(calculate, argv0_path, zip_path, prefix); @@ -1033,11 +1034,6 @@ calculate_init(PyCalculatePath *calculate, _PyPathConfig *pathconfig, calculate->home = pathconfig->home; calculate->path_env = _wgetenv(L"PATH"); - calculate->dll_path = _Py_GetDLLPath(); - if (calculate->dll_path == NULL) { - return _PyStatus_NO_MEMORY(); - } - calculate->pythonpath_env = config->pythonpath_env; return _PyStatus_OK(); @@ -1049,7 +1045,6 @@ calculate_free(PyCalculatePath *calculate) { PyMem_RawFree(calculate->machine_path); PyMem_RawFree(calculate->user_path); - PyMem_RawFree(calculate->dll_path); } @@ -1059,7 +1054,6 @@ calculate_free(PyCalculatePath *calculate) - PyConfig.pythonpath_env: PYTHONPATH environment variable - _PyPathConfig.home: Py_SetPythonHome() or PYTHONHOME environment variable - - DLL path: _Py_GetDLLPath() - PATH environment variable - __PYVENV_LAUNCHER__ environment variable - GetModuleFileNameW(NULL): fully qualified path of the executable file of @@ -1113,33 +1107,35 @@ int _Py_CheckPython3(void) { wchar_t py3path[MAXPATHLEN+1]; - wchar_t *s; if (python3_checked) { return hPython3 != NULL; } python3_checked = 1; /* If there is a python3.dll next to the python3y.dll, - assume this is a build tree; use that DLL */ - if (_Py_dll_path != NULL) { - wcscpy(py3path, _Py_dll_path); - } - else { - wcscpy(py3path, L""); - } - s = wcsrchr(py3path, L'\\'); - if (!s) { - s = py3path; + use that DLL */ + if (!get_dllpath(py3path)) { + reduce(py3path); + join(py3path, PY3_DLLNAME); + hPython3 = LoadLibraryExW(py3path, NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); + if (hPython3 != NULL) { + return 1; + } } - wcscpy(s, L"\\python3.dll"); - hPython3 = LoadLibraryExW(py3path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + + /* If we can locate python3.dll in our application dir, + use that DLL */ + hPython3 = LoadLibraryExW(PY3_DLLNAME, NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR); if (hPython3 != NULL) { return 1; } - /* Check sys.prefix\DLLs\python3.dll */ + /* For back-compat, also search {sys.prefix}\DLLs, though + that has not been a normal install layout for a while */ wcscpy(py3path, Py_GetPrefix()); - wcscat(py3path, L"\\DLLs\\python3.dll"); - hPython3 = LoadLibraryExW(py3path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + if (py3path[0]) { + join(py3path, L"DLLs\\" PY3_DLLNAME); + hPython3 = LoadLibraryExW(py3path, NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); + } return hPython3 != NULL; } -- cgit v1.2.3-65-gdbad