Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

python3: patch CVE-2024-9287 #10959

Open
wants to merge 1 commit into
base: 3.0-dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
343 changes: 343 additions & 0 deletions SPECS/python3/CVE-2024-9287.patch
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

6 changes: 5 additions & 1 deletion SPECS/python3/python3.spec
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
Summary: A high-level scripting language
Name: python3
Version: 3.12.3
Release: 5%{?dist}
Release: 6%{?dist}
License: PSF
Vendor: Microsoft Corporation
Distribution: Azure Linux
Expand All @@ -22,6 +22,7 @@ Patch2: CVE-2024-6923.patch
Patch3: CVE-2024-6232.patch
Patch4: CVE-2024-8088.patch
Patch5: CVE-2024-12254.patch
Patch6: CVE-2024-9287.patch

BuildRequires: bzip2-devel
BuildRequires: expat-devel >= 2.1.0
Expand Down Expand Up @@ -243,6 +244,9 @@ rm -rf %{buildroot}%{_bindir}/__pycache__
%{_libdir}/python%{majmin}/test/*

%changelog
* Wed Dec 18 2024 Saul Paredes <[email protected]> - 3.12.3-6
- Patch CVE-2024-9287

* Mon Dec 10 2024 Ankita Pareek <[email protected]> - 3.12.3-5
- Patch CVE-2024-12254

Expand Down
6 changes: 3 additions & 3 deletions toolkit/resources/manifests/package/pkggen_core_aarch64.txt
Original file line number Diff line number Diff line change
Expand Up @@ -240,9 +240,9 @@ ca-certificates-base-3.0.0-7.azl3.noarch.rpm
ca-certificates-3.0.0-7.azl3.noarch.rpm
dwz-0.14-2.azl3.aarch64.rpm
unzip-6.0-21.azl3.aarch64.rpm
python3-3.12.3-5.azl3.aarch64.rpm
python3-devel-3.12.3-5.azl3.aarch64.rpm
python3-libs-3.12.3-5.azl3.aarch64.rpm
python3-3.12.3-6.azl3.aarch64.rpm
python3-devel-3.12.3-6.azl3.aarch64.rpm
python3-libs-3.12.3-6.azl3.aarch64.rpm
python3-setuptools-69.0.3-4.azl3.noarch.rpm
python3-pygments-2.7.4-2.azl3.noarch.rpm
which-2.21-8.azl3.aarch64.rpm
Expand Down
6 changes: 3 additions & 3 deletions toolkit/resources/manifests/package/pkggen_core_x86_64.txt
Original file line number Diff line number Diff line change
Expand Up @@ -240,9 +240,9 @@ ca-certificates-base-3.0.0-7.azl3.noarch.rpm
ca-certificates-3.0.0-7.azl3.noarch.rpm
dwz-0.14-2.azl3.x86_64.rpm
unzip-6.0-21.azl3.x86_64.rpm
python3-3.12.3-5.azl3.x86_64.rpm
python3-devel-3.12.3-5.azl3.x86_64.rpm
python3-libs-3.12.3-5.azl3.x86_64.rpm
python3-3.12.3-6.azl3.x86_64.rpm
python3-devel-3.12.3-6.azl3.x86_64.rpm
python3-libs-3.12.3-6.azl3.x86_64.rpm
python3-setuptools-69.0.3-4.azl3.noarch.rpm
python3-pygments-2.7.4-2.azl3.noarch.rpm
which-2.21-8.azl3.x86_64.rpm
Expand Down
Loading
Loading