summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Dower <steve.dower@python.org>2023-02-09 10:34:52 +0000
committerGitHub <noreply@github.com>2023-02-09 11:34:52 +0100
commitc7fdc9c743d23b3c77ab4b1261748b8e395c298a (patch)
tree4e0a4f17f0edc004f081c33b79dae36d347a05e6
parentecfed4f9cc711b6843f6b0fc46b241ba0d3fd0d1 (diff)
downloadcpython-git-c7fdc9c743d23b3c77ab4b1261748b8e395c298a.tar.gz
[3.7] gh-101283: Improved fallback logic for subprocess with shell=True on Windows (GH-101286) (#101713)
Co-authored-by: Oleg Iarygin <oleg@arhadthedev.net> Co-authored-by: Ɓukasz Langa <lukasz@langa.pl> Co-authored-by: Oleg Iarygin <dralife@yandex.ru>
-rw-r--r--Doc/library/subprocess.rst43
-rw-r--r--Lib/subprocess.py18
-rw-r--r--Misc/NEWS.d/next/Security/2023-01-24-16-12-00.gh-issue-101283.9tqu39.rst3
3 files changed, 63 insertions, 1 deletions
diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst
index 9f2a056628..4c51f4f1f0 100644
--- a/Doc/library/subprocess.rst
+++ b/Doc/library/subprocess.rst
@@ -111,6 +111,14 @@ compatibility with older versions, see the :ref:`call-function-trio` section.
Added the *text* parameter, as a more understandable alias of *universal_newlines*.
Added the *capture_output* parameter.
+ .. versionchanged:: 3.7.17
+
+ Changed Windows shell search order for ``shell=True``. The current
+ directory and ``%PATH%`` are replaced with ``%COMSPEC%`` and
+ ``%SystemRoot%\System32\cmd.exe``. As a result, dropping a
+ malicious program named ``cmd.exe`` into a current directory no
+ longer works.
+
.. class:: CompletedProcess
The return value from :func:`run`, representing a process that has finished.
@@ -442,6 +450,17 @@ functions.
:program:`ps`. If ``shell=True``, on POSIX the *executable* argument
specifies a replacement shell for the default :file:`/bin/sh`.
+ .. versionchanged:: 3.6
+ *executable* parameter accepts a :term:`path-like object` on POSIX.
+
+ .. versionchanged:: 3.7.17
+
+ Changed Windows shell search order for ``shell=True``. The current
+ directory and ``%PATH%`` are replaced with ``%COMSPEC%`` and
+ ``%SystemRoot%\System32\cmd.exe``. As a result, dropping a
+ malicious program named ``cmd.exe`` into a current directory no
+ longer works.
+
*stdin*, *stdout* and *stderr* specify the executed program's standard input,
standard output and standard error file handles, respectively. Valid values
are :data:`PIPE`, :data:`DEVNULL`, an existing file descriptor (a positive
@@ -1032,6 +1051,14 @@ calls these functions.
.. versionchanged:: 3.3
*timeout* was added.
+ .. versionchanged:: 3.7.17
+
+ Changed Windows shell search order for ``shell=True``. The current
+ directory and ``%PATH%`` are replaced with ``%COMSPEC%`` and
+ ``%SystemRoot%\System32\cmd.exe``. As a result, dropping a
+ malicious program named ``cmd.exe`` into a current directory no
+ longer works.
+
.. function:: check_call(args, *, stdin=None, stdout=None, stderr=None, \
shell=False, cwd=None, timeout=None, \
**other_popen_kwargs)
@@ -1062,6 +1089,14 @@ calls these functions.
.. versionchanged:: 3.3
*timeout* was added.
+ .. versionchanged:: 3.7.17
+
+ Changed Windows shell search order for ``shell=True``. The current
+ directory and ``%PATH%`` are replaced with ``%COMSPEC%`` and
+ ``%SystemRoot%\System32\cmd.exe``. As a result, dropping a
+ malicious program named ``cmd.exe`` into a current directory no
+ longer works.
+
.. function:: check_output(args, *, stdin=None, stderr=None, shell=False, \
cwd=None, encoding=None, errors=None, \
@@ -1116,6 +1151,14 @@ calls these functions.
.. versionadded:: 3.7
*text* was added as a more readable alias for *universal_newlines*.
+ .. versionchanged:: 3.7.17
+
+ Changed Windows shell search order for ``shell=True``. The current
+ directory and ``%PATH%`` are replaced with ``%COMSPEC%`` and
+ ``%SystemRoot%\System32\cmd.exe``. As a result, dropping a
+ malicious program named ``cmd.exe`` into a current directory no
+ longer works.
+
.. _subprocess-replacements:
diff --git a/Lib/subprocess.py b/Lib/subprocess.py
index 3f99be551c..fd67945b7e 100644
--- a/Lib/subprocess.py
+++ b/Lib/subprocess.py
@@ -1192,7 +1192,23 @@ class Popen(object):
if shell:
startupinfo.dwFlags |= _winapi.STARTF_USESHOWWINDOW
startupinfo.wShowWindow = _winapi.SW_HIDE
- comspec = os.environ.get("COMSPEC", "cmd.exe")
+ if not executable:
+ # gh-101283: without a fully-qualified path, before Windows
+ # checks the system directories, it first looks in the
+ # application directory, and also the current directory if
+ # NeedCurrentDirectoryForExePathW(ExeName) is true, so try
+ # to avoid executing unqualified "cmd.exe".
+ comspec = os.environ.get('ComSpec')
+ if not comspec:
+ system_root = os.environ.get('SystemRoot', '')
+ comspec = os.path.join(system_root, 'System32', 'cmd.exe')
+ if not os.path.isabs(comspec):
+ raise FileNotFoundError('shell not found: neither %ComSpec% nor %SystemRoot% is set')
+ if os.path.isabs(comspec):
+ executable = comspec
+ else:
+ comspec = executable
+
args = '{} /c "{}"'.format (comspec, args)
# Start the process
diff --git a/Misc/NEWS.d/next/Security/2023-01-24-16-12-00.gh-issue-101283.9tqu39.rst b/Misc/NEWS.d/next/Security/2023-01-24-16-12-00.gh-issue-101283.9tqu39.rst
new file mode 100644
index 0000000000..0efdfa1023
--- /dev/null
+++ b/Misc/NEWS.d/next/Security/2023-01-24-16-12-00.gh-issue-101283.9tqu39.rst
@@ -0,0 +1,3 @@
+:class:`subprocess.Popen` now uses a safer approach to find
+``cmd.exe`` when launching with ``shell=True``. Patch by Eryk Sun,
+based on a patch by Oleg Iarygin.