Skip to content

Commit 51b079a

Browse files
Update Lib/subprocess.py
1 parent e8ce85d commit 51b079a

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

114+
.. versionchanged:: 3.11.2
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.
@@ -488,6 +496,14 @@ functions.
488496
*executable* parameter accepts a bytes and :term:`path-like object`
489497
on Windows.
490498

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

1179+
.. versionchanged:: 3.11.2
1180+
1181+
Changed Windows shell search order for ``shell=True``. The current
1182+
directory and ``%PATH%`` are replaced with ``%COMSPEC%`` and
1183+
``%SystemRoot%\System32\cmd.exe``. As a result, dropping a
1184+
malicious program named ``cmd.exe`` into a current directory no
1185+
longer works.
1186+
11631187
.. function:: check_call(args, *, stdin=None, stdout=None, stderr=None, \
11641188
shell=False, cwd=None, timeout=None, \
11651189
**other_popen_kwargs)
@@ -1192,6 +1216,14 @@ calls these functions.
11921216
.. versionchanged:: 3.3
11931217
*timeout* was added.
11941218

1219+
.. versionchanged:: 3.11.2
1220+
1221+
Changed Windows shell search order for ``shell=True``. The current
1222+
directory and ``%PATH%`` are replaced with ``%COMSPEC%`` and
1223+
``%SystemRoot%\System32\cmd.exe``. As a result, dropping a
1224+
malicious program named ``cmd.exe`` into a current directory no
1225+
longer works.
1226+
11951227

11961228
.. function:: check_output(args, *, stdin=None, stderr=None, shell=False, \
11971229
cwd=None, encoding=None, errors=None, \
@@ -1247,6 +1279,14 @@ calls these functions.
12471279
.. versionadded:: 3.7
12481280
*text* was added as a more readable alias for *universal_newlines*.
12491281

1282+
.. versionchanged:: 3.11.2
1283+
1284+
Changed Windows shell search order for ``shell=True``. The current
1285+
directory and ``%PATH%`` are replaced with ``%COMSPEC%`` and
1286+
``%SystemRoot%\System32\cmd.exe``. As a result, dropping a
1287+
malicious program named ``cmd.exe`` into a current directory no
1288+
longer works.
1289+
12501290

12511291
.. _subprocess-replacements:
12521292

Lib/subprocess.py

+17-1
Original file line numberDiff line numberDiff line change
@@ -1480,7 +1480,23 @@ def _execute_child(self, args, executable, preexec_fn, close_fds,
14801480
if shell:
14811481
startupinfo.dwFlags |= _winapi.STARTF_USESHOWWINDOW
14821482
startupinfo.wShowWindow = _winapi.SW_HIDE
1483-
comspec = os.environ.get("COMSPEC", "cmd.exe")
1483+
if not executable:
1484+
# gh-101283: without a fully-qualified path, before Windows
1485+
# checks the system directories, it first looks in the
1486+
# application directory, and also the current directory if
1487+
# NeedCurrentDirectoryForExePathW(ExeName) is true, so try
1488+
# to avoid executing unqualified "cmd.exe".
1489+
comspec = os.environ.get('ComSpec')
1490+
if not comspec:
1491+
system_root = os.environ.get('SystemRoot', '')
1492+
comspec = os.path.join(system_root, 'System32', 'cmd.exe')
1493+
if not os.path.isabs(comspec):
1494+
raise FileNotFoundError('shell not found: neither %ComSpec% nor %SystemRoot% is set')
1495+
if os.path.isabs(comspec):
1496+
executable = comspec
1497+
else:
1498+
comspec = executable
1499+
14841500
args = '{} /c "{}"'.format (comspec, args)
14851501

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