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
This commit is contained in:
Steve Dower 2020-07-06 17:32:00 +01:00 committed by GitHub
parent deb016224c
commit dcbaa1b49c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 150 additions and 137 deletions

View file

@ -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;
if (i == 0) {
dest[0] = '\0';
return -1;
}
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';
}
}
while (i > 0 && src[i] != '.' && !is_sep(src[i]))
--i;
if (i == 0) {
dest[0] = '\0';
return -1;
}
if (is_sep(src[i])) {
i = src_len;
}
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 @@ done:
#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);
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;
}
}
else {
wcscpy(py3path, L"");
}
s = wcsrchr(py3path, L'\\');
if (!s) {
s = py3path;
}
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;
}