Skip to content

Commit 9889de3

Browse files
Apply suggestions from code review
1 parent c63d7c9 commit 9889de3

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
@@ -110,6 +110,14 @@ underlying :class:`Popen` interface can be used directly.
110110
Added the *text* parameter, as a more understandable alias of *universal_newlines*.
111111
Added the *capture_output* parameter.
112112

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

115123
The return value from :func:`run`, representing a process that has finished.
@@ -486,6 +494,14 @@ functions.
486494
*executable* parameter accepts a bytes and :term:`path-like object`
487495
on Windows.
488496

497+
.. versionchanged:: 3.10.11
498+
499+
Changed Windows shell search order for ``shell=True``. The current
500+
directory and ``%PATH%`` are replaced with ``%COMSPEC%`` and
501+
``%SystemRoot%\System32\cmd.exe``. As a result, dropping a
502+
malicious program named ``cmd.exe`` into a current directory no
503+
longer works.
504+
489505
*stdin*, *stdout* and *stderr* specify the executed program's standard input,
490506
standard output and standard error file handles, respectively. Valid values
491507
are :data:`PIPE`, :data:`DEVNULL`, an existing file descriptor (a positive
@@ -1152,6 +1168,14 @@ calls these functions.
11521168
.. versionchanged:: 3.3
11531169
*timeout* was added.
11541170

1171+
.. versionchanged:: 3.10.11
1172+
1173+
Changed Windows shell search order for ``shell=True``. The current
1174+
directory and ``%PATH%`` are replaced with ``%COMSPEC%`` and
1175+
``%SystemRoot%\System32\cmd.exe``. As a result, dropping a
1176+
malicious program named ``cmd.exe`` into a current directory no
1177+
longer works.
1178+
11551179
.. function:: check_call(args, *, stdin=None, stdout=None, stderr=None, \
11561180
shell=False, cwd=None, timeout=None, \
11571181
**other_popen_kwargs)
@@ -1184,6 +1208,14 @@ calls these functions.
11841208
.. versionchanged:: 3.3
11851209
*timeout* was added.
11861210

1211+
.. versionchanged:: 3.10.11
1212+
1213+
Changed Windows shell search order for ``shell=True``. The current
1214+
directory and ``%PATH%`` are replaced with ``%COMSPEC%`` and
1215+
``%SystemRoot%\System32\cmd.exe``. As a result, dropping a
1216+
malicious program named ``cmd.exe`` into a current directory no
1217+
longer works.
1218+
11871219

11881220
.. function:: check_output(args, *, stdin=None, stderr=None, shell=False, \
11891221
cwd=None, encoding=None, errors=None, \
@@ -1239,6 +1271,14 @@ calls these functions.
12391271
.. versionadded:: 3.7
12401272
*text* was added as a more readable alias for *universal_newlines*.
12411273

1274+
.. versionchanged:: 3.10.11
1275+
1276+
Changed Windows shell search order for ``shell=True``. The current
1277+
directory and ``%PATH%`` are replaced with ``%COMSPEC%`` and
1278+
``%SystemRoot%\System32\cmd.exe``. As a result, dropping a
1279+
malicious program named ``cmd.exe`` into a current directory no
1280+
longer works.
1281+
12421282

12431283
.. _subprocess-replacements:
12441284

Lib/subprocess.py

+17-1
Original file line numberDiff line numberDiff line change
@@ -1427,7 +1427,23 @@ def _execute_child(self, args, executable, preexec_fn, close_fds,
14271427
if shell:
14281428
startupinfo.dwFlags |= _winapi.STARTF_USESHOWWINDOW
14291429
startupinfo.wShowWindow = _winapi.SW_HIDE
1430-
comspec = os.environ.get("COMSPEC", "cmd.exe")
1430+
if not executable:
1431+
# gh-101283: without a fully-qualified path, before Windows
1432+
# checks the system directories, it first looks in the
1433+
# application directory, and also the current directory if
1434+
# NeedCurrentDirectoryForExePathW(ExeName) is true, so try
1435+
# to avoid executing unqualified "cmd.exe".
1436+
comspec = os.environ.get('ComSpec')
1437+
if not comspec:
1438+
system_root = os.environ.get('SystemRoot', '')
1439+
comspec = os.path.join(system_root, 'System32', 'cmd.exe')
1440+
if not os.path.isabs(comspec):
1441+
raise FileNotFoundError('shell not found: neither %ComSpec% nor %SystemRoot% is set')
1442+
if os.path.isabs(comspec):
1443+
executable = comspec
1444+
else:
1445+
comspec = executable
1446+
14311447
args = '{} /c "{}"'.format (comspec, args)
14321448

14331449
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)