Compare commits

...

1 Commits
c8-beta ... c9

Author SHA1 Message Date
ece0379eb3 import UBI python3.12-wheel-0.41.2-3.el9_7.1 2026-02-04 19:29:46 +00:00
2 changed files with 93 additions and 31 deletions

View File

@ -0,0 +1,85 @@
From 24ab89cdacfa68857b4c7b5fb5234a75193dc941 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Alex=20Gr=C3=B6nholm?= <alex.gronholm@nextday.fi>
Date: Thu, 22 Jan 2026 01:41:14 +0200
Subject: [PATCH] Fixed security issue around wheel unpack (#675)
A maliciously crafted wheel could cause the permissions of a file outside the unpack tree to be altered.
Fixes CVE-2026-24049.
(cherry picked from commit 7a7d2de96b22a9adf9208afcc9547e1001569fef)
---
docs/news.rst | 5 +++++
src/wheel/cli/unpack.py | 4 ++--
tests/cli/test_unpack.py | 23 +++++++++++++++++++++++
3 files changed, 30 insertions(+), 2 deletions(-)
diff --git a/docs/news.rst b/docs/news.rst
index 9e5488a..1033520 100644
--- a/docs/news.rst
+++ b/docs/news.rst
@@ -1,6 +1,11 @@
Release Notes
=============
+**BACKPORTS**
+
+- Fixed ``wheel unpack`` potentially altering the permissions of files outside of the
+ destination tree with maliciously crafted wheels (CVE-2026-24049)
+
**0.41.2 (2023-08-22)**
- Fixed platform tag detection for GraalPy and 32-bit python running on an aarch64
diff --git a/src/wheel/cli/unpack.py b/src/wheel/cli/unpack.py
index d48840e..83dc742 100644
--- a/src/wheel/cli/unpack.py
+++ b/src/wheel/cli/unpack.py
@@ -19,12 +19,12 @@ def unpack(path: str, dest: str = ".") -> None:
destination = Path(dest) / namever
print(f"Unpacking to: {destination}...", end="", flush=True)
for zinfo in wf.filelist:
- wf.extract(zinfo, destination)
+ target_path = Path(wf.extract(zinfo, destination))
# Set permissions to the same values as they were set in the archive
# We have to do this manually due to
# https://github.com/python/cpython/issues/59999
permissions = zinfo.external_attr >> 16 & 0o777
- destination.joinpath(zinfo.filename).chmod(permissions)
+ target_path.chmod(permissions)
print("OK")
diff --git a/tests/cli/test_unpack.py b/tests/cli/test_unpack.py
index ae584af..951ba29 100644
--- a/tests/cli/test_unpack.py
+++ b/tests/cli/test_unpack.py
@@ -34,3 +34,26 @@ def test_unpack_executable_bit(tmp_path):
unpack(str(wheel_path), str(tmp_path))
assert not script_path.is_dir()
assert stat.S_IMODE(script_path.stat().st_mode) == 0o755
+
+
+@pytest.mark.skipif(
+ platform.system() == "Windows", reason="Windows does not support chmod()"
+)
+def test_chmod_outside_unpack_tree(tmp_path_factory: TempPathFactory) -> None:
+ wheel_path = tmp_path_factory.mktemp("build") / "test-1.0-py3-none-any.whl"
+ with WheelFile(wheel_path, "w") as wf:
+ wf.writestr(
+ "test-1.0.dist-info/METADATA",
+ "Metadata-Version: 2.4\nName: test\nVersion: 1.0\n",
+ )
+ wf.writestr("../../system-file", b"malicious data")
+
+ extract_root_path = tmp_path_factory.mktemp("extract")
+ system_file = extract_root_path / "system-file"
+ extract_path = extract_root_path / "subdir"
+ system_file.write_bytes(b"important data")
+ system_file.chmod(0o755)
+ unpack(str(wheel_path), str(extract_path))
+
+ assert system_file.read_bytes() == b"important data"
+ assert stat.S_IMODE(system_file.stat().st_mode) == 0o755
--
2.52.0

View File

@ -1,11 +1,6 @@
%global __python3 /usr/bin/python3.12 %global __python3 /usr/bin/python3.12
%global python3_pkgversion 3.12 %global python3_pkgversion 3.12
# Workaround for https://issues.redhat.com/browse/CS-1907
# By defining the %%{__bootstrap} value,
# we prevent misconfigured Koji putting a literal %%{__bootstrap} in %%dist.
%{!?__bootstrap:%global __bootstrap %{nil}}
# The function of bootstrap is that it installs the wheel by unzipping it # The function of bootstrap is that it installs the wheel by unzipping it
%bcond_with bootstrap %bcond_with bootstrap
# Default: when bootstrapping -> disable tests # Default: when bootstrapping -> disable tests
@ -25,7 +20,7 @@
Name: python%{python3_pkgversion}-%{pypi_name} Name: python%{python3_pkgversion}-%{pypi_name}
Version: 0.41.2 Version: 0.41.2
Release: 3%{?dist} Release: 3%{?dist}.1
Summary: Built-package format for Python Summary: Built-package format for Python
# packaging is ASL 2.0 or BSD # packaging is ASL 2.0 or BSD
@ -35,6 +30,9 @@ Source0: %{url}/archive/%{version}/%{pypi_name}-%{version}.tar.gz
# This is used in bootstrap mode where we manually install the wheel and # This is used in bootstrap mode where we manually install the wheel and
# entrypoints # entrypoints
Source1: wheel-entrypoint Source1: wheel-entrypoint
# Security fix for CVE-2026-24049: Privilege Escalation or Arbitrary Code Execution via malicious wheel file unpacking
# https://github.com/pypa/wheel/commit/7a7d2d (from 0.46.2+)
Patch1: CVE-2026-24049.patch
BuildArch: noarch BuildArch: noarch
BuildRequires: python%{python3_pkgversion}-devel BuildRequires: python%{python3_pkgversion}-devel
@ -68,14 +66,6 @@ Provides: bundled(python%{python3_version}dist(packaging)) = 23
%{bundled} %{bundled}
# Require alternatives version that implements the --keep-foreign flag and fixes rhbz#2203820
Requires(postun): alternatives >= 1.19.2-1
# python3.12 installs the alternatives master symlink to which we attach a slave
Requires: python%{python3_pkgversion}
Requires(post): python%{python3_pkgversion}
Requires(postun): python%{python3_pkgversion}
%global _description %{expand: %global _description %{expand:
Wheel is the reference implementation of the Python wheel packaging standard, Wheel is the reference implementation of the Python wheel packaging standard,
as defined in PEP 427. as defined in PEP 427.
@ -124,8 +114,6 @@ mv %{buildroot}%{_bindir}/%{pypi_name}{,-%{python3_version}}
ln -s %{pypi_name}-%{python3_version} %{buildroot}%{_bindir}/%{pypi_name}-3 ln -s %{pypi_name}-%{python3_version} %{buildroot}%{_bindir}/%{pypi_name}-3
ln -s %{pypi_name}-3 %{buildroot}%{_bindir}/%{pypi_name} ln -s %{pypi_name}-3 %{buildroot}%{_bindir}/%{pypi_name}
%endif %endif
# Create an empty file to be used by `alternatives`
touch %{buildroot}%{_bindir}/%{pypi_name}-3
mkdir -p %{buildroot}%{python_wheel_dir} mkdir -p %{buildroot}%{python_wheel_dir}
install -p dist/%{python_wheel_name} -t %{buildroot}%{python_wheel_dir} install -p dist/%{python_wheel_name} -t %{buildroot}%{python_wheel_dir}
@ -140,20 +128,6 @@ install -p dist/%{python_wheel_name} -t %{buildroot}%{python_wheel_dir}
%pytest -v --ignore build %pytest -v --ignore build
%endif %endif
%post -n python%{python3_pkgversion}-%{pypi_name}
alternatives --add-slave python3 %{_bindir}/python%{python3_version} \
%{_bindir}/%{pypi_name}-3 \
%{pypi_name}-3 \
%{_bindir}/%{pypi_name}-%{python3_version}
%postun -n python%{python3_pkgversion}-%{pypi_name}
# Do this only during uninstall process (not during update)
if [ $1 -eq 0 ]; then
alternatives --keep-foreign --remove-slave python3 %{_bindir}/python%{python3_version} \
%{pypi_name}-3
fi
%files -n python%{python3_pkgversion}-%{pypi_name} %files -n python%{python3_pkgversion}-%{pypi_name}
%license LICENSE.txt %license LICENSE.txt
%doc README.rst %doc README.rst
@ -162,7 +136,6 @@ fi
%{_bindir}/%{pypi_name} %{_bindir}/%{pypi_name}
%{_bindir}/%{pypi_name}-3 %{_bindir}/%{pypi_name}-3
%endif %endif
%ghost %{_bindir}/%{pypi_name}-3
%{python3_sitelib}/%{pypi_name}*/ %{python3_sitelib}/%{pypi_name}*/
%files -n %{python_wheel_pkg_prefix}-%{pypi_name}-wheel %files -n %{python_wheel_pkg_prefix}-%{pypi_name}-wheel
@ -172,6 +145,10 @@ fi
%{python_wheel_dir}/%{python_wheel_name} %{python_wheel_dir}/%{python_wheel_name}
%changelog %changelog
* Mon Jan 26 2026 Miro Hrončok <mhroncok@redhat.com> - 0.41.2-3.1
- Security fix for CVE-2026-24049
Resolves: RHEL-143652
* Tue Jan 23 2024 Miro Hrončok <mhroncok@redhat.com> - 0.41.2-3 * Tue Jan 23 2024 Miro Hrončok <mhroncok@redhat.com> - 0.41.2-3
- Rebuilt for timestamp .pyc invalidation mode - Rebuilt for timestamp .pyc invalidation mode