[Python-checkins] [3.6] bpo-29778: Ensure python3.dll is loaded from correct locations when Python is embedded (GH-21298) (#21354)

Steve Dower webhook-mailer at python.org
Mon Jul 6 14:55:48 EDT 2020


https://github.com/python/cpython/commit/46cbf6148a46883110883488d3e9febbe46ba861
commit: 46cbf6148a46883110883488d3e9febbe46ba861
branch: 3.6
author: Steve Dower <steve.dower at python.org>
committer: GitHub <noreply at github.com>
date: 2020-07-06T14:55:43-04:00
summary:

[3.6] bpo-29778: Ensure python3.dll is loaded from correct locations when Python is embedded (GH-21298) (#21354)

* bpo-29778: Ensure python3.dll is loaded from correct locations when Python is embedded (GH-21298)

* bpo-29778: Ensure python3.dll is loaded from correct locations when Python is embedded.

* Add CVE number

* Updates for 3.6

files:
A Misc/NEWS.d/next/Security/2020-07-03-17-21-37.bpo-29778.cR_fGS.rst
M PC/getpathp.c
M PCbuild/pyproject.props
M PCbuild/python.props
M Python/dynload_win.c

diff --git a/Misc/NEWS.d/next/Security/2020-07-03-17-21-37.bpo-29778.cR_fGS.rst b/Misc/NEWS.d/next/Security/2020-07-03-17-21-37.bpo-29778.cR_fGS.rst
new file mode 100644
index 0000000000000..998ffb1ee6667
--- /dev/null
+++ b/Misc/NEWS.d/next/Security/2020-07-03-17-21-37.bpo-29778.cR_fGS.rst
@@ -0,0 +1,2 @@
+Ensure :file:`python3.dll` is loaded from correct locations when Python is
+embedded (CVE-2020-15523).
diff --git a/PC/getpathp.c b/PC/getpathp.c
index e86c376fb4d34..f6f362c7f9c1d 100644
--- a/PC/getpathp.c
+++ b/PC/getpathp.c
@@ -118,7 +118,6 @@
 
 static wchar_t prefix[MAXPATHLEN+1];
 static wchar_t progpath[MAXPATHLEN+1];
-static wchar_t dllpath[MAXPATHLEN+1];
 static wchar_t *module_search_path = NULL;
 
 
@@ -150,24 +149,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;
     }
@@ -304,6 +316,20 @@ search_for_prefix(wchar_t *argv0_path, const wchar_t *landmark)
     return 0;
 }
 
+
+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.*/
@@ -467,15 +493,6 @@ get_progpath(void)
     wchar_t *path = _wgetenv(L"PATH");
     wchar_t *prog = Py_GetProgramName();
 
-#ifdef Py_ENABLE_SHARED
-    extern HANDLE PyWin_DLLhModule;
-    /* static init of progpath ensures final char remains \0 */
-    if (PyWin_DLLhModule)
-        if (!GetModuleFileNameW(PyWin_DLLhModule, dllpath, MAXPATHLEN))
-            dllpath[0] = 0;
-#else
-    dllpath[0] = 0;
-#endif
     if (GetModuleFileNameW(NULL, modulepath, MAXPATHLEN)) {
         canonicalize(progpath, modulepath);
         return;
@@ -693,7 +710,7 @@ calculate_path(void)
     {
         wchar_t spbuffer[MAXPATHLEN+1];
 
-        if ((dllpath[0] && !change_ext(spbuffer, dllpath, L"._pth") && exists(spbuffer)) ||
+        if ((!get_dllpath(spbuffer) && !change_ext(spbuffer, spbuffer, L"._pth") && exists(spbuffer)) ||
             (progpath[0] && !change_ext(spbuffer, progpath, L"._pth") && exists(spbuffer))) {
 
             if (!read_pth_file(spbuffer, prefix, &Py_IsolatedFlag, &Py_NoSiteFlag)) {
@@ -737,7 +754,11 @@ calculate_path(void)
     }
 
     /* Calculate zip archive path from DLL or exe path */
-    change_ext(zip_path, dllpath[0] ? dllpath : progpath, L".zip");
+    if (!get_dllpath(zip_path)) {
+        change_ext(zip_path, zip_path, L".zip");
+    } else {
+        change_ext(zip_path, progpath, L".zip");
+    }
 
     if (pythonhome == NULL || *pythonhome == '\0') {
         if (zip_path[0] && exists(zip_path)) {
@@ -919,8 +940,6 @@ calculate_path(void)
 }
 
 
-/* External interface */
-
 void
 Py_SetPath(const wchar_t *path)
 {
@@ -981,25 +1000,39 @@ int
 _Py_CheckPython3()
 {
     wchar_t py3path[MAXPATHLEN+1];
-    wchar_t *s;
-    if (python3_checked)
+    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 */
-    wcscpy(py3path, dllpath);
-    s = wcsrchr(py3path, L'\\');
-    if (!s)
-        s = py3path;
-    wcscpy(s, L"\\python3.dll");
-    hPython3 = LoadLibraryExW(py3path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
-    if (hPython3 != NULL)
-        return 1;
+       use that DLL */
+    if (!get_dllpath(py3path)) {
+        reduce(py3path);
+        join(py3path, PY3_DLLNAME);
+        hPython3 = LoadLibraryExW(py3path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
+        if (hPython3 != NULL) {
+            return 1;
+        }
+    }
+
+    /* If we can locate python3.dll in our application dir,
+       use that DLL */
+    wcscpy(py3path, Py_GetPrefix());
+    if (py3path[0]) {
+        join(py3path, PY3_DLLNAME);
+        hPython3 = LoadLibraryExW(py3path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
+        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_WITH_ALTERED_SEARCH_PATH);
+    }
     return hPython3 != NULL;
 }
diff --git a/PCbuild/pyproject.props b/PCbuild/pyproject.props
index 1602ebf5ec973..104a9d8e623a7 100644
--- a/PCbuild/pyproject.props
+++ b/PCbuild/pyproject.props
@@ -24,12 +24,12 @@
     <_PlatformPreprocessorDefinition>_WIN32;</_PlatformPreprocessorDefinition>
     <_PlatformPreprocessorDefinition Condition="$(Platform) == 'x64'">_WIN64;_M_X64;</_PlatformPreprocessorDefinition>
     <_PydPreprocessorDefinition Condition="$(TargetExt) == '.pyd'">Py_BUILD_CORE_MODULE;</_PydPreprocessorDefinition>
+    <_Py3NamePreprocessorDefinition>PY3_DLLNAME=L"$(Py3DllName)";</_Py3NamePreprocessorDefinition>
   </PropertyGroup>
   <ItemDefinitionGroup>
     <ClCompile>
       <AdditionalIncludeDirectories>$(PySourcePath)Include;$(PySourcePath)PC;$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>WIN32;$(_PlatformPreprocessorDefinition)$(_DebugPreprocessorDefinition)$(_PydPreprocessorDefinition)%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      
+      <PreprocessorDefinitions>WIN32;$(_Py3NamePreprocessorDefinition)$(_PlatformPreprocessorDefinition)$(_DebugPreprocessorDefinition)$(_PydPreprocessorDefinition)%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <Optimization>MaxSpeed</Optimization>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <StringPooling>true</StringPooling>
diff --git a/PCbuild/python.props b/PCbuild/python.props
index 3022ca50c247a..b82425ea9710d 100644
--- a/PCbuild/python.props
+++ b/PCbuild/python.props
@@ -175,6 +175,8 @@
     
     <!-- The name of the resulting pythonXY.dll (without the extension) -->
     <PyDllName>python$(MajorVersionNumber)$(MinorVersionNumber)$(PyDebugExt)</PyDllName>
+    <!-- The name of the resulting pythonX.dll (without the extension) -->
+    <Py3DllName>python3$(PyDebugExt)</Py3DllName>
 
     <!-- The version and platform tag to include in .pyd filenames -->
     <PydTag Condition="$(ArchName) == 'win32'">.cp$(MajorVersionNumber)$(MinorVersionNumber)-win32</PydTag>
diff --git a/Python/dynload_win.c b/Python/dynload_win.c
index 0fdf77f55280c..a307188823cfe 100644
--- a/Python/dynload_win.c
+++ b/Python/dynload_win.c
@@ -192,9 +192,7 @@ dl_funcptr _PyImport_FindSharedFuncptrWindows(const char *prefix,
     char funcname[258], *import_python;
     const wchar_t *wpathname;
 
-#ifndef _DEBUG
     _Py_CheckPython3();
-#endif
 
     wpathname = _PyUnicode_AsUnicode(pathname);
     if (wpathname == NULL)



More information about the Python-checkins mailing list