forked from microsoft/azurelinux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Taken from python/cpython#126185 which is a 3.12 backport of python/cpython#124712 Signed-off-by: Saul Paredes <[email protected]>
- Loading branch information
Showing
6 changed files
with
368 additions
and
21 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,343 @@ | ||
From 697b53a06eca774b496190be50dc5879984b407f Mon Sep 17 00:00:00 2001 | ||
From: Saul Paredes <[email protected]> | ||
Date: Wed, 6 Nov 2024 16:43:27 -0800 | ||
Subject: [PATCH] python3: patch CVE-2024-9287 | ||
|
||
Adapted from https://github.com/python/cpython/commit/8450b2482586857d689b6658f08de9c8179af7db (fixed whitespaces) | ||
|
||
Signed-off-by: Saul Paredes <[email protected]> | ||
--- | ||
Lib/test/test_venv.py | 81 +++++++++++++++++++ | ||
Lib/venv/__init__.py | 42 ++++++++-- | ||
Lib/venv/scripts/common/activate | 10 +-- | ||
Lib/venv/scripts/nt/activate.bat | 30 +++---- | ||
Lib/venv/scripts/posix/activate.csh | 8 +- | ||
Lib/venv/scripts/posix/activate.fish | 8 +- | ||
...-09-28-02-03-04.gh-issue-124651.bLBGtH.rst | 1 + | ||
7 files changed, 147 insertions(+), 33 deletions(-) | ||
create mode 100644 Misc/NEWS.d/next/Library/2024-09-28-02-03-04.gh-issue-124651.bLBGtH.rst | ||
|
||
diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py | ||
index 2f44176..e01cf03 100644 | ||
--- a/Lib/test/test_venv.py | ||
+++ b/Lib/test/test_venv.py | ||
@@ -17,6 +17,7 @@ import subprocess | ||
import sys | ||
import sysconfig | ||
import tempfile | ||
+import shlex | ||
from test.support import (captured_stdout, captured_stderr, | ||
skip_if_broken_multiprocessing_synchronize, verbose, | ||
requires_subprocess, is_emscripten, is_wasi, | ||
@@ -96,6 +97,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.""" | ||
|
||
@@ -445,6 +450,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 2173c9b..53486d5 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',) | ||
@@ -395,11 +396,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): | ||
@@ -439,6 +470,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 d5914e0..47602ca 100644 | ||
--- a/Lib/venv/scripts/common/activate | ||
+++ b/Lib/venv/scripts/common/activate | ||
@@ -39,14 +39,14 @@ deactivate nondestructive | ||
if [ "${OSTYPE:-}" = "cygwin" ] || [ "${OSTYPE:-}" = "msys" ] ; then | ||
# transform D:\path\to\venv to /d/path/to/venv on MSYS | ||
# and to /cygdrive/d/path/to/venv on Cygwin | ||
- export VIRTUAL_ENV=$(cygpath "__VENV_DIR__") | ||
+ export VIRTUAL_ENV=$(cygpath __VENV_DIR__) | ||
else | ||
# use the path as-is | ||
- export VIRTUAL_ENV="__VENV_DIR__" | ||
+ export VIRTUAL_ENV=__VENV_DIR__ | ||
fi | ||
|
||
_OLD_VIRTUAL_PATH="$PATH" | ||
-PATH="$VIRTUAL_ENV/__VENV_BIN_NAME__:$PATH" | ||
+PATH="$VIRTUAL_ENV/"__VENV_BIN_NAME__":$PATH" | ||
export PATH | ||
|
||
# unset PYTHONHOME if set | ||
@@ -59,9 +59,9 @@ fi | ||
|
||
if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then | ||
_OLD_VIRTUAL_PS1="${PS1:-}" | ||
- PS1="__VENV_PROMPT__${PS1:-}" | ||
+ PS1=__VENV_PROMPT__"${PS1:-}" | ||
export PS1 | ||
- VIRTUAL_ENV_PROMPT="__VENV_PROMPT__" | ||
+ VIRTUAL_ENV_PROMPT=__VENV_PROMPT__ | ||
export VIRTUAL_ENV_PROMPT | ||
fi | ||
|
||
diff --git a/Lib/venv/scripts/nt/activate.bat b/Lib/venv/scripts/nt/activate.bat | ||
index 5daa45a..0b3e583 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,14 +21,14 @@ 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% | ||
-set VIRTUAL_ENV_PROMPT=__VENV_PROMPT__ | ||
- | ||
-: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%" | ||
+set "VIRTUAL_ENV_PROMPT=__VENV_PROMPT__" | ||
+ | ||
+: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 5e8d66f..08f7929 100644 | ||
--- a/Lib/venv/scripts/posix/activate.csh | ||
+++ b/Lib/venv/scripts/posix/activate.csh | ||
@@ -9,17 +9,17 @@ 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" | ||
- setenv VIRTUAL_ENV_PROMPT "__VENV_PROMPT__" | ||
+ set prompt = __VENV_PROMPT__"$prompt" | ||
+ setenv VIRTUAL_ENV_PROMPT __VENV_PROMPT__ | ||
endif | ||
|
||
alias pydoc python -m pydoc | ||
diff --git a/Lib/venv/scripts/posix/activate.fish b/Lib/venv/scripts/posix/activate.fish | ||
index 91ad644..508cab0 100644 | ||
--- a/Lib/venv/scripts/posix/activate.fish | ||
+++ b/Lib/venv/scripts/posix/activate.fish | ||
@@ -33,10 +33,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 | ||
@@ -56,7 +56,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" | . | ||
@@ -65,5 +65,5 @@ if test -z "$VIRTUAL_ENV_DISABLE_PROMPT" | ||
end | ||
|
||
set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV" | ||
- set -gx VIRTUAL_ENV_PROMPT "__VENV_PROMPT__" | ||
+ set -gx VIRTUAL_ENV_PROMPT __VENV_PROMPT__ | ||
end | ||
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. | ||
-- | ||
2.25.1 | ||
|
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 |
---|---|---|
|
@@ -6,7 +6,7 @@ | |
Summary: A high-level scripting language | ||
Name: python3 | ||
Version: 3.12.3 | ||
Release: 4%{?dist} | ||
Release: 5%{?dist} | ||
License: PSF | ||
Vendor: Microsoft Corporation | ||
Distribution: Azure Linux | ||
|
@@ -21,6 +21,7 @@ Patch1: CVE-2024-7592.patch | |
Patch2: CVE-2024-6923.patch | ||
Patch3: CVE-2024-6232.patch | ||
Patch4: CVE-2024-8088.patch | ||
Patch5: CVE-2024-9287.patch | ||
|
||
BuildRequires: bzip2-devel | ||
BuildRequires: expat-devel >= 2.1.0 | ||
|
@@ -242,6 +243,9 @@ rm -rf %{buildroot}%{_bindir}/__pycache__ | |
%{_libdir}/python%{majmin}/test/* | ||
|
||
%changelog | ||
* Wed Nov 06 2024 Saul Paredes <[email protected]> - 3.12.3-5 | ||
- Patch CVE-2024-9287 | ||
|
||
* Fri Sep 20 2024 Himaja Kesari <[email protected]> - 3.12.3-4 | ||
- Patch CVE-2024-6232 and CVE-2024-8088 | ||
|
||
|
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.