]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.7] gh-101283: Improved fallback logic for subprocess with shell=True on Windows...
authorSteve Dower <steve.dower@python.org>
Thu, 9 Feb 2023 10:34:52 +0000 (10:34 +0000)
committerGitHub <noreply@github.com>
Thu, 9 Feb 2023 10:34:52 +0000 (11:34 +0100)
Co-authored-by: Oleg Iarygin <oleg@arhadthedev.net>
Co-authored-by: Ɓukasz Langa <lukasz@langa.pl>
Co-authored-by: Oleg Iarygin <dralife@yandex.ru>
Doc/library/subprocess.rst
Lib/subprocess.py
Misc/NEWS.d/next/Security/2023-01-24-16-12-00.gh-issue-101283.9tqu39.rst [new file with mode: 0644]

index 9f2a05662860ee27f86233f6288d3b6f4bcbf22d..4c51f4f1f03c2197f40e92bd86f8bc1247a34f4d 100644 (file)
@@ -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:
 
index 3f99be551c5152d2278deb2ef6bc94ed4362f5c4..fd67945b7e4b339ea8e8c8258396b0a23aef267c 100644 (file)
@@ -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 (file)
index 0000000..0efdfa1
--- /dev/null
@@ -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.