Skip to content
This repository was archived by the owner on Feb 13, 2025. It is now read-only.

Commit d7b0850

Browse files
author
Anselm Kruis
committed
Merge commit 46cbf61 into branch 3.6-slp.
2 parents c78ad55 + 46cbf61 commit d7b0850

File tree

5 files changed

+81
-46
lines changed

5 files changed

+81
-46
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Ensure :file:`python3.dll` is loaded from correct locations when Python is
2+
embedded (CVE-2020-15523).

PC/getpathp.c

Lines changed: 75 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,6 @@
118118

119119
static wchar_t prefix[MAXPATHLEN+1];
120120
static wchar_t progpath[MAXPATHLEN+1];
121-
static wchar_t dllpath[MAXPATHLEN+1];
122121
static wchar_t *module_search_path = NULL;
123122

124123

@@ -150,24 +149,37 @@ reduce(wchar_t *dir)
150149
static int
151150
change_ext(wchar_t *dest, const wchar_t *src, const wchar_t *ext)
152151
{
153-
size_t src_len = wcsnlen_s(src, MAXPATHLEN+1);
154-
size_t i = src_len;
155-
if (i >= MAXPATHLEN+1)
156-
Py_FatalError("buffer overflow in getpathp.c's reduce()");
152+
if (src && src != dest) {
153+
size_t src_len = wcsnlen_s(src, MAXPATHLEN+1);
154+
size_t i = src_len;
155+
if (i >= MAXPATHLEN+1) {
156+
Py_FatalError("buffer overflow in getpathp.c's reduce()");
157+
}
157158

158-
while (i > 0 && src[i] != '.' && !is_sep(src[i]))
159-
--i;
159+
while (i > 0 && src[i] != '.' && !is_sep(src[i]))
160+
--i;
160161

161-
if (i == 0) {
162-
dest[0] = '\0';
163-
return -1;
164-
}
162+
if (i == 0) {
163+
dest[0] = '\0';
164+
return -1;
165+
}
165166

166-
if (is_sep(src[i]))
167-
i = src_len;
167+
if (is_sep(src[i])) {
168+
i = src_len;
169+
}
170+
171+
if (wcsncpy_s(dest, MAXPATHLEN+1, src, i)) {
172+
dest[0] = '\0';
173+
return -1;
174+
}
175+
} else {
176+
wchar_t *s = wcsrchr(dest, L'.');
177+
if (s) {
178+
s[0] = '\0';
179+
}
180+
}
168181

169-
if (wcsncpy_s(dest, MAXPATHLEN+1, src, i) ||
170-
wcscat_s(dest, MAXPATHLEN+1, ext)) {
182+
if (wcscat_s(dest, MAXPATHLEN+1, ext)) {
171183
dest[0] = '\0';
172184
return -1;
173185
}
@@ -304,6 +316,20 @@ search_for_prefix(wchar_t *argv0_path, const wchar_t *landmark)
304316
return 0;
305317
}
306318

319+
320+
static int
321+
get_dllpath(wchar_t *dllpath)
322+
{
323+
#ifdef Py_ENABLE_SHARED
324+
extern HANDLE PyWin_DLLhModule;
325+
if (PyWin_DLLhModule && GetModuleFileNameW(PyWin_DLLhModule, dllpath, MAXPATHLEN)) {
326+
return 0;
327+
}
328+
#endif
329+
return -1;
330+
}
331+
332+
307333
#ifdef Py_ENABLE_SHARED
308334

309335
/* a string loaded from the DLL at startup.*/
@@ -467,15 +493,6 @@ get_progpath(void)
467493
wchar_t *path = _wgetenv(L"PATH");
468494
wchar_t *prog = Py_GetProgramName();
469495

470-
#ifdef Py_ENABLE_SHARED
471-
extern HANDLE PyWin_DLLhModule;
472-
/* static init of progpath ensures final char remains \0 */
473-
if (PyWin_DLLhModule)
474-
if (!GetModuleFileNameW(PyWin_DLLhModule, dllpath, MAXPATHLEN))
475-
dllpath[0] = 0;
476-
#else
477-
dllpath[0] = 0;
478-
#endif
479496
if (GetModuleFileNameW(NULL, modulepath, MAXPATHLEN)) {
480497
canonicalize(progpath, modulepath);
481498
return;
@@ -693,7 +710,7 @@ calculate_path(void)
693710
{
694711
wchar_t spbuffer[MAXPATHLEN+1];
695712

696-
if ((dllpath[0] && !change_ext(spbuffer, dllpath, L"._pth") && exists(spbuffer)) ||
713+
if ((!get_dllpath(spbuffer) && !change_ext(spbuffer, spbuffer, L"._pth") && exists(spbuffer)) ||
697714
(progpath[0] && !change_ext(spbuffer, progpath, L"._pth") && exists(spbuffer))) {
698715

699716
if (!read_pth_file(spbuffer, prefix, &Py_IsolatedFlag, &Py_NoSiteFlag)) {
@@ -737,7 +754,11 @@ calculate_path(void)
737754
}
738755

739756
/* Calculate zip archive path from DLL or exe path */
740-
change_ext(zip_path, dllpath[0] ? dllpath : progpath, L".zip");
757+
if (!get_dllpath(zip_path)) {
758+
change_ext(zip_path, zip_path, L".zip");
759+
} else {
760+
change_ext(zip_path, progpath, L".zip");
761+
}
741762

742763
if (pythonhome == NULL || *pythonhome == '\0') {
743764
if (zip_path[0] && exists(zip_path)) {
@@ -919,8 +940,6 @@ calculate_path(void)
919940
}
920941

921942

922-
/* External interface */
923-
924943
void
925944
Py_SetPath(const wchar_t *path)
926945
{
@@ -981,25 +1000,39 @@ int
9811000
_Py_CheckPython3()
9821001
{
9831002
wchar_t py3path[MAXPATHLEN+1];
984-
wchar_t *s;
985-
if (python3_checked)
1003+
if (python3_checked) {
9861004
return hPython3 != NULL;
1005+
}
9871006
python3_checked = 1;
9881007

9891008
/* If there is a python3.dll next to the python3y.dll,
990-
assume this is a build tree; use that DLL */
991-
wcscpy(py3path, dllpath);
992-
s = wcsrchr(py3path, L'\\');
993-
if (!s)
994-
s = py3path;
995-
wcscpy(s, L"\\python3.dll");
996-
hPython3 = LoadLibraryExW(py3path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
997-
if (hPython3 != NULL)
998-
return 1;
1009+
use that DLL */
1010+
if (!get_dllpath(py3path)) {
1011+
reduce(py3path);
1012+
join(py3path, PY3_DLLNAME);
1013+
hPython3 = LoadLibraryExW(py3path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
1014+
if (hPython3 != NULL) {
1015+
return 1;
1016+
}
1017+
}
1018+
1019+
/* If we can locate python3.dll in our application dir,
1020+
use that DLL */
1021+
wcscpy(py3path, Py_GetPrefix());
1022+
if (py3path[0]) {
1023+
join(py3path, PY3_DLLNAME);
1024+
hPython3 = LoadLibraryExW(py3path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
1025+
if (hPython3 != NULL) {
1026+
return 1;
1027+
}
1028+
}
9991029

1000-
/* Check sys.prefix\DLLs\python3.dll */
1030+
/* For back-compat, also search {sys.prefix}\DLLs, though
1031+
that has not been a normal install layout for a while */
10011032
wcscpy(py3path, Py_GetPrefix());
1002-
wcscat(py3path, L"\\DLLs\\python3.dll");
1003-
hPython3 = LoadLibraryExW(py3path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
1033+
if (py3path[0]) {
1034+
join(py3path, L"DLLs\\" PY3_DLLNAME);
1035+
hPython3 = LoadLibraryExW(py3path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
1036+
}
10041037
return hPython3 != NULL;
10051038
}

PCbuild/pyproject.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@
2424
<_PlatformPreprocessorDefinition>_WIN32;</_PlatformPreprocessorDefinition>
2525
<_PlatformPreprocessorDefinition Condition="$(Platform) == 'x64'">_WIN64;_M_X64;</_PlatformPreprocessorDefinition>
2626
<_PydPreprocessorDefinition Condition="$(TargetExt) == '.pyd'">Py_BUILD_CORE_MODULE;</_PydPreprocessorDefinition>
27+
<_Py3NamePreprocessorDefinition>PY3_DLLNAME=L"$(Py3DllName)";</_Py3NamePreprocessorDefinition>
2728
</PropertyGroup>
2829
<ItemDefinitionGroup>
2930
<ClCompile>
3031
<AdditionalIncludeDirectories>$(PySourcePath)Include;$(PySourcePath)PC;$(PySourcePath)Stackless;$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
31-
<PreprocessorDefinitions>WIN32;$(_PlatformPreprocessorDefinition)$(_DebugPreprocessorDefinition)$(_PydPreprocessorDefinition)%(PreprocessorDefinitions)</PreprocessorDefinitions>
32-
32+
<PreprocessorDefinitions>WIN32;$(_Py3NamePreprocessorDefinition)$(_PlatformPreprocessorDefinition)$(_DebugPreprocessorDefinition)$(_PydPreprocessorDefinition)%(PreprocessorDefinitions)</PreprocessorDefinitions>
3333
<Optimization>MaxSpeed</Optimization>
3434
<IntrinsicFunctions>true</IntrinsicFunctions>
3535
<StringPooling>true</StringPooling>

PCbuild/python.props

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,8 @@
175175

176176
<!-- The name of the resulting pythonXY.dll (without the extension) -->
177177
<PyDllName>python$(MajorVersionNumber)$(MinorVersionNumber)$(PyDebugExt)</PyDllName>
178+
<!-- The name of the resulting pythonX.dll (without the extension) -->
179+
<Py3DllName>python3$(PyDebugExt)</Py3DllName>
178180

179181
<!-- The version and platform tag to include in .pyd filenames -->
180182
<PydTag Condition="$(ArchName) == 'win32'">.cp$(MajorVersionNumber)$(MinorVersionNumber)-win32</PydTag>

Python/dynload_win.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,9 +192,7 @@ dl_funcptr _PyImport_FindSharedFuncptrWindows(const char *prefix,
192192
char funcname[258], *import_python;
193193
const wchar_t *wpathname;
194194

195-
#ifndef _DEBUG
196195
_Py_CheckPython3();
197-
#endif
198196

199197
wpathname = _PyUnicode_AsUnicode(pathname);
200198
if (wpathname == NULL)

0 commit comments

Comments
 (0)