-
Notifications
You must be signed in to change notification settings - Fork 568
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
python3: patch CVE-2024-9287 [Medium] (#12659)
Co-authored-by: jslobodzian <[email protected]> (cherry picked from commit 9fecd40)
- Loading branch information
1 parent
327db28
commit 7df816e
Showing
6 changed files
with
336 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,303 @@ | ||
diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py | ||
index 480cb29..871b831 100644 | ||
--- a/Lib/test/test_venv.py | ||
+++ b/Lib/test/test_venv.py | ||
@@ -14,6 +14,7 @@ import struct | ||
import subprocess | ||
import sys | ||
import tempfile | ||
+import shlex | ||
from test.support import (captured_stdout, captured_stderr, requires_zlib, | ||
can_symlink, EnvironmentVarGuard, rmtree, | ||
import_module, | ||
@@ -85,6 +86,10 @@ class BaseTest(unittest.TestCase): | ||
result = f.read() | ||
return result | ||
|
||
+ def assertEndsWith(self, string, tail): | ||
+ if not string.endswith(tail): | ||
+ self.fail(f"String {string!r} does not end with {tail!r}") | ||
+ | ||
class BasicTest(BaseTest): | ||
"""Test venv module functionality.""" | ||
|
||
@@ -342,6 +347,82 @@ class BasicTest(BaseTest): | ||
'import sys; print(sys.executable)']) | ||
self.assertEqual(out.strip(), envpy.encode()) | ||
|
||
+ # gh-124651: test quoted strings | ||
+ @unittest.skipIf(os.name == 'nt', 'contains invalid characters on Windows') | ||
+ def test_special_chars_bash(self): | ||
+ """ | ||
+ Test that the template strings are quoted properly (bash) | ||
+ """ | ||
+ rmtree(self.env_dir) | ||
+ bash = shutil.which('bash') | ||
+ if bash is None: | ||
+ self.skipTest('bash required for this test') | ||
+ env_name = '"\';&&$e|\'"' | ||
+ env_dir = os.path.join(os.path.realpath(self.env_dir), env_name) | ||
+ builder = venv.EnvBuilder(clear=True) | ||
+ builder.create(env_dir) | ||
+ activate = os.path.join(env_dir, self.bindir, 'activate') | ||
+ test_script = os.path.join(self.env_dir, 'test_special_chars.sh') | ||
+ with open(test_script, "w") as f: | ||
+ f.write(f'source {shlex.quote(activate)}\n' | ||
+ 'python -c \'import sys; print(sys.executable)\'\n' | ||
+ 'python -c \'import os; print(os.environ["VIRTUAL_ENV"])\'\n' | ||
+ 'deactivate\n') | ||
+ out, err = check_output([bash, test_script]) | ||
+ lines = out.splitlines() | ||
+ self.assertTrue(env_name.encode() in lines[0]) | ||
+ self.assertEndsWith(lines[1], env_name.encode()) | ||
+ | ||
+ # gh-124651: test quoted strings | ||
+ @unittest.skipIf(os.name == 'nt', 'contains invalid characters on Windows') | ||
+ def test_special_chars_csh(self): | ||
+ """ | ||
+ Test that the template strings are quoted properly (csh) | ||
+ """ | ||
+ rmtree(self.env_dir) | ||
+ csh = shutil.which('tcsh') or shutil.which('csh') | ||
+ if csh is None: | ||
+ self.skipTest('csh required for this test') | ||
+ env_name = '"\';&&$e|\'"' | ||
+ env_dir = os.path.join(os.path.realpath(self.env_dir), env_name) | ||
+ builder = venv.EnvBuilder(clear=True) | ||
+ builder.create(env_dir) | ||
+ activate = os.path.join(env_dir, self.bindir, 'activate.csh') | ||
+ test_script = os.path.join(self.env_dir, 'test_special_chars.csh') | ||
+ with open(test_script, "w") as f: | ||
+ f.write(f'source {shlex.quote(activate)}\n' | ||
+ 'python -c \'import sys; print(sys.executable)\'\n' | ||
+ 'python -c \'import os; print(os.environ["VIRTUAL_ENV"])\'\n' | ||
+ 'deactivate\n') | ||
+ out, err = check_output([csh, test_script]) | ||
+ lines = out.splitlines() | ||
+ self.assertTrue(env_name.encode() in lines[0]) | ||
+ self.assertEndsWith(lines[1], env_name.encode()) | ||
+ | ||
+ # gh-124651: test quoted strings on Windows | ||
+ @unittest.skipUnless(os.name == 'nt', 'only relevant on Windows') | ||
+ def test_special_chars_windows(self): | ||
+ """ | ||
+ Test that the template strings are quoted properly on Windows | ||
+ """ | ||
+ rmtree(self.env_dir) | ||
+ env_name = "'&&^$e" | ||
+ env_dir = os.path.join(os.path.realpath(self.env_dir), env_name) | ||
+ builder = venv.EnvBuilder(clear=True) | ||
+ builder.create(env_dir) | ||
+ activate = os.path.join(env_dir, self.bindir, 'activate.bat') | ||
+ test_batch = os.path.join(self.env_dir, 'test_special_chars.bat') | ||
+ with open(test_batch, "w") as f: | ||
+ f.write('@echo off\n' | ||
+ f'"{activate}" & ' | ||
+ f'{self.exe} -c "import sys; print(sys.executable)" & ' | ||
+ f'{self.exe} -c "import os; print(os.environ[\'VIRTUAL_ENV\'])" & ' | ||
+ 'deactivate') | ||
+ out, err = check_output([test_batch]) | ||
+ lines = out.splitlines() | ||
+ self.assertTrue(env_name.encode() in lines[0]) | ||
+ self.assertEndsWith(lines[1], env_name.encode()) | ||
+ | ||
@unittest.skipUnless(os.name == 'nt', 'only relevant on Windows') | ||
def test_unicode_in_batch_file(self): | ||
""" | ||
diff --git a/Lib/venv/__init__.py b/Lib/venv/__init__.py | ||
index 6f1af29..2996331 100644 | ||
--- a/Lib/venv/__init__.py | ||
+++ b/Lib/venv/__init__.py | ||
@@ -11,6 +11,7 @@ import subprocess | ||
import sys | ||
import sysconfig | ||
import types | ||
+import shlex | ||
|
||
|
||
CORE_VENV_DEPS = ('pip', 'setuptools') | ||
@@ -348,11 +349,41 @@ class EnvBuilder: | ||
:param context: The information for the environment creation request | ||
being processed. | ||
""" | ||
- text = text.replace('__VENV_DIR__', context.env_dir) | ||
- text = text.replace('__VENV_NAME__', context.env_name) | ||
- text = text.replace('__VENV_PROMPT__', context.prompt) | ||
- text = text.replace('__VENV_BIN_NAME__', context.bin_name) | ||
- text = text.replace('__VENV_PYTHON__', context.env_exe) | ||
+ replacements = { | ||
+ '__VENV_DIR__': context.env_dir, | ||
+ '__VENV_NAME__': context.env_name, | ||
+ '__VENV_PROMPT__': context.prompt, | ||
+ '__VENV_BIN_NAME__': context.bin_name, | ||
+ '__VENV_PYTHON__': context.env_exe, | ||
+ } | ||
+ | ||
+ def quote_ps1(s): | ||
+ """ | ||
+ This should satisfy PowerShell quoting rules [1], unless the quoted | ||
+ string is passed directly to Windows native commands [2]. | ||
+ [1]: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_quoting_rules | ||
+ [2]: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_parsing#passing-arguments-that-contain-quote-characters | ||
+ """ | ||
+ s = s.replace("'", "''") | ||
+ return f"'{s}'" | ||
+ | ||
+ def quote_bat(s): | ||
+ return s | ||
+ | ||
+ # gh-124651: need to quote the template strings properly | ||
+ quote = shlex.quote | ||
+ script_path = context.script_path | ||
+ if script_path.endswith('.ps1'): | ||
+ quote = quote_ps1 | ||
+ elif script_path.endswith('.bat'): | ||
+ quote = quote_bat | ||
+ else: | ||
+ # fallbacks to POSIX shell compliant quote | ||
+ quote = shlex.quote | ||
+ | ||
+ replacements = {key: quote(s) for key, s in replacements.items()} | ||
+ for key, quoted in replacements.items(): | ||
+ text = text.replace(key, quoted) | ||
return text | ||
|
||
def install_scripts(self, context, path): | ||
@@ -392,6 +423,7 @@ class EnvBuilder: | ||
with open(srcfile, 'rb') as f: | ||
data = f.read() | ||
if not srcfile.endswith(('.exe', '.pdb')): | ||
+ context.script_path = srcfile | ||
try: | ||
data = data.decode('utf-8') | ||
data = self.replace_variables(data, context) | ||
diff --git a/Lib/venv/scripts/common/activate b/Lib/venv/scripts/common/activate | ||
index 45af353..1d116ca 100644 | ||
--- a/Lib/venv/scripts/common/activate | ||
+++ b/Lib/venv/scripts/common/activate | ||
@@ -37,11 +37,11 @@ deactivate () { | ||
# unset irrelevant variables | ||
deactivate nondestructive | ||
|
||
-VIRTUAL_ENV="__VENV_DIR__" | ||
+VIRTUAL_ENV=__VENV_DIR__ | ||
export VIRTUAL_ENV | ||
|
||
_OLD_VIRTUAL_PATH="$PATH" | ||
-PATH="$VIRTUAL_ENV/__VENV_BIN_NAME__:$PATH" | ||
+PATH="$VIRTUAL_ENV/"__VENV_BIN_NAME__":$PATH" | ||
export PATH | ||
|
||
# unset PYTHONHOME if set | ||
@@ -54,7 +54,7 @@ fi | ||
|
||
if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then | ||
_OLD_VIRTUAL_PS1="${PS1:-}" | ||
- PS1="__VENV_PROMPT__${PS1:-}" | ||
+ PS1=__VENV_PROMPT__"${PS1:-}" | ||
export PS1 | ||
fi | ||
|
||
diff --git a/Lib/venv/scripts/nt/activate.bat b/Lib/venv/scripts/nt/activate.bat | ||
index f61413e..f910aa1 100644 | ||
--- a/Lib/venv/scripts/nt/activate.bat | ||
+++ b/Lib/venv/scripts/nt/activate.bat | ||
@@ -5,13 +5,13 @@ for /f "tokens=2 delims=:." %%a in ('"%SystemRoot%\System32\chcp.com"') do ( | ||
set _OLD_CODEPAGE=%%a | ||
) | ||
if defined _OLD_CODEPAGE ( | ||
- "%SystemRoot%\System32\chcp.com" 65001 > nul | ||
-) | ||
- | ||
-set VIRTUAL_ENV=__VENV_DIR__ | ||
- | ||
-if not defined PROMPT set PROMPT=$P$G | ||
- | ||
+ "%SystemRoot%\System32\chcp.com" 65001 > nul | ||
+) | ||
+ | ||
+set "VIRTUAL_ENV=__VENV_DIR__" | ||
+ | ||
+if not defined PROMPT set PROMPT=$P$G | ||
+ | ||
if defined _OLD_VIRTUAL_PROMPT set PROMPT=%_OLD_VIRTUAL_PROMPT% | ||
if defined _OLD_VIRTUAL_PYTHONHOME set PYTHONHOME=%_OLD_VIRTUAL_PYTHONHOME% | ||
|
||
@@ -21,13 +21,13 @@ set PROMPT=__VENV_PROMPT__%PROMPT% | ||
if defined PYTHONHOME set _OLD_VIRTUAL_PYTHONHOME=%PYTHONHOME% | ||
set PYTHONHOME= | ||
|
||
-if defined _OLD_VIRTUAL_PATH set PATH=%_OLD_VIRTUAL_PATH% | ||
-if not defined _OLD_VIRTUAL_PATH set _OLD_VIRTUAL_PATH=%PATH% | ||
- | ||
-set PATH=%VIRTUAL_ENV%\__VENV_BIN_NAME__;%PATH% | ||
- | ||
-:END | ||
-if defined _OLD_CODEPAGE ( | ||
+if defined _OLD_VIRTUAL_PATH set PATH=%_OLD_VIRTUAL_PATH% | ||
+if not defined _OLD_VIRTUAL_PATH set _OLD_VIRTUAL_PATH=%PATH% | ||
+ | ||
+set "PATH=%VIRTUAL_ENV%\__VENV_BIN_NAME__;%PATH%" | ||
+ | ||
+:END | ||
+if defined _OLD_CODEPAGE ( | ||
"%SystemRoot%\System32\chcp.com" %_OLD_CODEPAGE% > nul | ||
set _OLD_CODEPAGE= | ||
) | ||
diff --git a/Lib/venv/scripts/posix/activate.csh b/Lib/venv/scripts/posix/activate.csh | ||
index 68a0dc7..5130113 100644 | ||
--- a/Lib/venv/scripts/posix/activate.csh | ||
+++ b/Lib/venv/scripts/posix/activate.csh | ||
@@ -8,16 +8,16 @@ alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PA | ||
# Unset irrelevant variables. | ||
deactivate nondestructive | ||
|
||
-setenv VIRTUAL_ENV "__VENV_DIR__" | ||
+setenv VIRTUAL_ENV __VENV_DIR__ | ||
|
||
set _OLD_VIRTUAL_PATH="$PATH" | ||
-setenv PATH "$VIRTUAL_ENV/__VENV_BIN_NAME__:$PATH" | ||
+setenv PATH "$VIRTUAL_ENV/"__VENV_BIN_NAME__":$PATH" | ||
|
||
|
||
set _OLD_VIRTUAL_PROMPT="$prompt" | ||
|
||
if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then | ||
- set prompt = "__VENV_PROMPT__$prompt" | ||
+ set prompt = __VENV_PROMPT__"$prompt" | ||
endif | ||
|
||
alias pydoc python -m pydoc | ||
diff --git a/Lib/venv/scripts/posix/activate.fish b/Lib/venv/scripts/posix/activate.fish | ||
index 54b9ea5..62ab531 100644 | ||
--- a/Lib/venv/scripts/posix/activate.fish | ||
+++ b/Lib/venv/scripts/posix/activate.fish | ||
@@ -29,10 +29,10 @@ end | ||
# Unset irrelevant variables. | ||
deactivate nondestructive | ||
|
||
-set -gx VIRTUAL_ENV "__VENV_DIR__" | ||
+set -gx VIRTUAL_ENV __VENV_DIR__ | ||
|
||
set -gx _OLD_VIRTUAL_PATH $PATH | ||
-set -gx PATH "$VIRTUAL_ENV/__VENV_BIN_NAME__" $PATH | ||
+set -gx PATH "$VIRTUAL_ENV/"__VENV_BIN_NAME__ $PATH | ||
|
||
# Unset PYTHONHOME if set. | ||
if set -q PYTHONHOME | ||
@@ -52,7 +52,7 @@ if test -z "$VIRTUAL_ENV_DISABLE_PROMPT" | ||
set -l old_status $status | ||
|
||
# Output the venv prompt; color taken from the blue of the Python logo. | ||
- printf "%s%s%s" (set_color 4B8BBE) "__VENV_PROMPT__" (set_color normal) | ||
+ printf "%s%s%s" (set_color 4B8BBE) __VENV_PROMPT__ (set_color normal) | ||
|
||
# Restore the return status of the previous command. | ||
echo "exit $old_status" | . | ||
diff --git a/Misc/NEWS.d/next/Library/2024-09-28-02-03-04.gh-issue-124651.bLBGtH.rst b/Misc/NEWS.d/next/Library/2024-09-28-02-03-04.gh-issue-124651.bLBGtH.rst | ||
new file mode 100644 | ||
index 0000000..17fc917 | ||
--- /dev/null | ||
+++ b/Misc/NEWS.d/next/Library/2024-09-28-02-03-04.gh-issue-124651.bLBGtH.rst | ||
@@ -0,0 +1 @@ | ||
+Properly quote template strings in :mod:`venv` activation scripts. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,7 +12,7 @@ | |
Summary: A high-level scripting language | ||
Name: python3 | ||
Version: 3.9.19 | ||
Release: 10%{?dist} | ||
Release: 11%{?dist} | ||
License: PSF | ||
Vendor: Microsoft Corporation | ||
Distribution: Mariner | ||
|
@@ -31,6 +31,7 @@ Patch7: CVE-2024-11168.patch | |
Patch8: CVE-2024-6923.patch | ||
Patch9: CVE-2023-27043.patch | ||
Patch10: CVE-2025-0938.patch | ||
Patch11: CVE-2024-9287.patch | ||
# Patch for setuptools, resolved in 65.5.1 | ||
Patch1000: CVE-2022-40897.patch | ||
Patch1001: CVE-2024-6345.patch | ||
|
@@ -179,6 +180,7 @@ The test package contains all regression tests for Python as well as the modules | |
%patch8 -p1 | ||
%patch9 -p1 | ||
%patch10 -p1 | ||
%patch11 -p1 | ||
|
||
%build | ||
# Remove GCC specs and build environment linker scripts | ||
|
@@ -334,10 +336,13 @@ rm -rf %{buildroot}%{_bindir}/__pycache__ | |
%{_libdir}/python%{majmin}/test/* | ||
|
||
%changelog | ||
* Wed Feb 26 2025 Nadiia Dubchak <[email protected]> - 3.9.19-11 | ||
- Patch CVE-2024-9287 | ||
|
||
* Thu Feb 06 2025 Kanishk Bansal <[email protected]> - 3.9.19-10 | ||
- Patch CVE-2025-0938 | ||
|
||
* Mon Feb 03 2024 Bala <[email protected]> - 3.9.19-9 | ||
* Mon Feb 03 2025 Balakumaran Kannan <[email protected]> - 3.9.19-9 | ||
- Address CVE-2023-27043 by patching | ||
|
||
* Thu Nov 28 2024 Kanishk Bansal <[email protected]> - 3.9.19-8 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.