Skip to content

Commit

Permalink
pythongh-101283: Improved fallback logic for subprocess with shell=Tr…
Browse files Browse the repository at this point in the history
…ue on Windows (pythonGH-101286)
  • Loading branch information
arhadthedev authored and zooba committed Feb 8, 2023
1 parent ecfed4f commit e06a55e
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 1 deletion.
43 changes: 43 additions & 0 deletions Doc/library/subprocess.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.11.2

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.
Expand Down Expand Up @@ -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.11.2

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
Expand Down Expand Up @@ -1032,6 +1051,14 @@ calls these functions.
.. versionchanged:: 3.3
*timeout* was added.

.. versionchanged:: 3.11.2

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)
Expand Down Expand Up @@ -1062,6 +1089,14 @@ calls these functions.
.. versionchanged:: 3.3
*timeout* was added.

.. versionchanged:: 3.11.2

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, \
Expand Down Expand Up @@ -1116,6 +1151,14 @@ calls these functions.
.. versionadded:: 3.7
*text* was added as a more readable alias for *universal_newlines*.

.. versionchanged:: 3.11.2

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:

Expand Down
18 changes: 17 additions & 1 deletion Lib/subprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -1192,7 +1192,23 @@ def _execute_child(self, args, executable, preexec_fn, close_fds,
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
Expand Down
Original file line number Diff line number Diff line change
@@ -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.

0 comments on commit e06a55e

Please sign in to comment.