Skip to content

Commit 04cc427

Browse files
miss-islingtonarhadthedevzooba
authoredFeb 9, 2023
[3.9] gh-101283: Improved fallback logic for subprocess with shell=True on Windows (GH-101286) (#101709)
Co-authored-by: Oleg Iarygin <[email protected]> Co-authored-by: Steve Dower <[email protected]>
1 parent c33aaa9 commit 04cc427

File tree

3 files changed

+60
-1
lines changed

3 files changed

+60
-1
lines changed
 

‎Doc/library/subprocess.rst

+40
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,14 @@ compatibility with older versions, see the :ref:`call-function-trio` section.
111111
Added the *text* parameter, as a more understandable alias of *universal_newlines*.
112112
Added the *capture_output* parameter.
113113

114+
.. versionchanged:: 3.9.17
115+
116+
Changed Windows shell search order for ``shell=True``. The current
117+
directory and ``%PATH%`` are replaced with ``%COMSPEC%`` and
118+
``%SystemRoot%\System32\cmd.exe``. As a result, dropping a
119+
malicious program named ``cmd.exe`` into a current directory no
120+
longer works.
121+
114122
.. class:: CompletedProcess
115123

116124
The return value from :func:`run`, representing a process that has finished.
@@ -468,6 +476,14 @@ functions.
468476
*executable* parameter accepts a bytes and :term:`path-like object`
469477
on Windows.
470478

479+
.. versionchanged:: 3.9.17
480+
481+
Changed Windows shell search order for ``shell=True``. The current
482+
directory and ``%PATH%`` are replaced with ``%COMSPEC%`` and
483+
``%SystemRoot%\System32\cmd.exe``. As a result, dropping a
484+
malicious program named ``cmd.exe`` into a current directory no
485+
longer works.
486+
471487
*stdin*, *stdout* and *stderr* specify the executed program's standard input,
472488
standard output and standard error file handles, respectively. Valid values
473489
are :data:`PIPE`, :data:`DEVNULL`, an existing file descriptor (a positive
@@ -1126,6 +1142,14 @@ calls these functions.
11261142
.. versionchanged:: 3.3
11271143
*timeout* was added.
11281144

1145+
.. versionchanged:: 3.9.17
1146+
1147+
Changed Windows shell search order for ``shell=True``. The current
1148+
directory and ``%PATH%`` are replaced with ``%COMSPEC%`` and
1149+
``%SystemRoot%\System32\cmd.exe``. As a result, dropping a
1150+
malicious program named ``cmd.exe`` into a current directory no
1151+
longer works.
1152+
11291153
.. function:: check_call(args, *, stdin=None, stdout=None, stderr=None, \
11301154
shell=False, cwd=None, timeout=None, \
11311155
**other_popen_kwargs)
@@ -1158,6 +1182,14 @@ calls these functions.
11581182
.. versionchanged:: 3.3
11591183
*timeout* was added.
11601184

1185+
.. versionchanged:: 3.9.17
1186+
1187+
Changed Windows shell search order for ``shell=True``. The current
1188+
directory and ``%PATH%`` are replaced with ``%COMSPEC%`` and
1189+
``%SystemRoot%\System32\cmd.exe``. As a result, dropping a
1190+
malicious program named ``cmd.exe`` into a current directory no
1191+
longer works.
1192+
11611193

11621194
.. function:: check_output(args, *, stdin=None, stderr=None, shell=False, \
11631195
cwd=None, encoding=None, errors=None, \
@@ -1213,6 +1245,14 @@ calls these functions.
12131245
.. versionadded:: 3.7
12141246
*text* was added as a more readable alias for *universal_newlines*.
12151247

1248+
.. versionchanged:: 3.9.17
1249+
1250+
Changed Windows shell search order for ``shell=True``. The current
1251+
directory and ``%PATH%`` are replaced with ``%COMSPEC%`` and
1252+
``%SystemRoot%\System32\cmd.exe``. As a result, dropping a
1253+
malicious program named ``cmd.exe`` into a current directory no
1254+
longer works.
1255+
12161256

12171257
.. _subprocess-replacements:
12181258

‎Lib/subprocess.py

+17-1
Original file line numberDiff line numberDiff line change
@@ -1407,7 +1407,23 @@ def _execute_child(self, args, executable, preexec_fn, close_fds,
14071407
if shell:
14081408
startupinfo.dwFlags |= _winapi.STARTF_USESHOWWINDOW
14091409
startupinfo.wShowWindow = _winapi.SW_HIDE
1410-
comspec = os.environ.get("COMSPEC", "cmd.exe")
1410+
if not executable:
1411+
# gh-101283: without a fully-qualified path, before Windows
1412+
# checks the system directories, it first looks in the
1413+
# application directory, and also the current directory if
1414+
# NeedCurrentDirectoryForExePathW(ExeName) is true, so try
1415+
# to avoid executing unqualified "cmd.exe".
1416+
comspec = os.environ.get('ComSpec')
1417+
if not comspec:
1418+
system_root = os.environ.get('SystemRoot', '')
1419+
comspec = os.path.join(system_root, 'System32', 'cmd.exe')
1420+
if not os.path.isabs(comspec):
1421+
raise FileNotFoundError('shell not found: neither %ComSpec% nor %SystemRoot% is set')
1422+
if os.path.isabs(comspec):
1423+
executable = comspec
1424+
else:
1425+
comspec = executable
1426+
14111427
args = '{} /c "{}"'.format (comspec, args)
14121428

14131429
if cwd is not None:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:class:`subprocess.Popen` now uses a safer approach to find
2+
``cmd.exe`` when launching with ``shell=True``. Patch by Eryk Sun,
3+
based on a patch by Oleg Iarygin.

0 commit comments

Comments
 (0)
Please sign in to comment.