mirror of
https://git.yoctoproject.org/poky
synced 2026-09-25 07:36:23 +02:00
python3-pip: Fix CVE-2026-8643
Apply the primary upstream fix referenced in [4] with commit [1]. Then apply the two follow-up regression-fix commits [2] and [3]. The primary fix rejects entry-point names that escape the configured scripts directory. The follow-up fixes handle doubled-slash roots and reuse the existing directory-containment helper. [1]8eb178480b[2]7ff8bdd81e[3]fa7854f6b3[4] https://github.com/advisories/GHSA-wf93-45jw-7689 (From OE-Core rev: 2c276677d619bc6205872eb2b5a9948a4605d8ea) Signed-off-by: Hetvi Thakar <hthakar@cisco.com> Signed-off-by: Yoann Congal <yoann.congal@smile.fr> Signed-off-by: Paul Barker <paul@pbarker.dev>
This commit is contained in:
committed by
Paul Barker
parent
97fdca2021
commit
b24d56a0b3
@@ -0,0 +1,34 @@
|
||||
From 7cac095948e86d8a0e0e17de6b763727e9b051ac Mon Sep 17 00:00:00 2001
|
||||
From: Damian Shaw <damian.peter.shaw@gmail.com>
|
||||
Date: Mon, 18 May 2026 23:22:51 -0400
|
||||
Subject: [PATCH] Fix is_within_directory for doubled-slash roots
|
||||
|
||||
CVE: CVE-2026-8643
|
||||
Upstream-Status: Backport [https://github.com/pypa/pip/commit/7ff8bdd81ec5edca2bebf78ad8506dda710d6af5]
|
||||
|
||||
Backport Changes:
|
||||
- Omit tests/unit/test_utils_unpacking.py because the pip 24.0 PyPI sdist used
|
||||
by this recipe does not ship the upstream tests directory.
|
||||
|
||||
(cherry picked from commit 7ff8bdd81ec5edca2bebf78ad8506dda710d6af5)
|
||||
Signed-off-by: Hetvi Thakar <hthakar@cisco.com>
|
||||
---
|
||||
src/pip/_internal/utils/unpacking.py | 3 +--
|
||||
1 file changed, 1 insertion(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/pip/_internal/utils/unpacking.py b/src/pip/_internal/utils/unpacking.py
|
||||
index 0b26525fb..188f27e67 100644
|
||||
--- a/src/pip/_internal/utils/unpacking.py
|
||||
+++ b/src/pip/_internal/utils/unpacking.py
|
||||
@@ -81,8 +81,7 @@ def is_within_directory(directory: str, target: str) -> bool:
|
||||
abs_directory = os.path.abspath(directory)
|
||||
abs_target = os.path.abspath(target)
|
||||
|
||||
- prefix = os.path.commonpath([abs_directory, abs_target])
|
||||
- return prefix == abs_directory
|
||||
+ return abs_target == abs_directory or abs_target.startswith(abs_directory + os.sep)
|
||||
|
||||
|
||||
def set_extracted_file_to_default_mode_plus_executable(path: str) -> None:
|
||||
--
|
||||
2.35.6
|
||||
@@ -0,0 +1,69 @@
|
||||
From b77d10eee5805aea3055e434e08ad1f105bd330c Mon Sep 17 00:00:00 2001
|
||||
From: Damian <damian.peter.shaw@gmail.com>
|
||||
Date: Sun, 24 May 2026 14:54:47 -0400
|
||||
Subject: [PATCH] Use is_within_directory for entry point check
|
||||
|
||||
CVE: CVE-2026-8643
|
||||
Upstream-Status: Backport [https://github.com/pypa/pip/commit/fa7854f6b37113a2c4698cdde902e1fcc9bebdd5]
|
||||
|
||||
Backport Changes:
|
||||
- Omit tests/unit/test_wheel.py because the pip 24.0 PyPI sdist used by this
|
||||
recipe does not ship the upstream tests directory.
|
||||
|
||||
(cherry picked from commit fa7854f6b37113a2c4698cdde902e1fcc9bebdd5)
|
||||
Signed-off-by: Hetvi Thakar <hthakar@cisco.com>
|
||||
---
|
||||
src/pip/_internal/operations/install/wheel.py | 18 ++----
|
||||
src/pip/_internal/utils/unpacking.py | 1 +
|
||||
2 files changed, 7 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/src/pip/_internal/operations/install/wheel.py b/src/pip/_internal/operations/install/wheel.py
|
||||
index 8a36a66ae..ce3e8efe6 100644
|
||||
--- a/src/pip/_internal/operations/install/wheel.py
|
||||
+++ b/src/pip/_internal/operations/install/wheel.py
|
||||
@@ -409,17 +409,6 @@ class MissingCallableSuffix(InstallationError):
|
||||
)
|
||||
|
||||
|
||||
-def _script_within_dir(name: str, scripts_dir: str) -> bool:
|
||||
- """Return whether script ``name`` resolves to a path inside the ``scripts_dir``.
|
||||
-
|
||||
- distlib joins the entry point name onto the scripts directory, so a name
|
||||
- with path separators or ``..`` components can resolve elsewhere.
|
||||
- """
|
||||
- root = os.path.normpath(scripts_dir)
|
||||
- dest = os.path.normpath(os.path.join(scripts_dir, name))
|
||||
- return dest.startswith(root + os.sep)
|
||||
-
|
||||
-
|
||||
def _raise_for_invalid_entrypoint(specification: str, scripts_dir: str) -> None:
|
||||
entry = get_export_entry(specification)
|
||||
if entry is None:
|
||||
@@ -428,7 +417,12 @@ def _raise_for_invalid_entrypoint(specification: str, scripts_dir: str) -> None:
|
||||
if entry.suffix is None:
|
||||
raise MissingCallableSuffix(str(entry))
|
||||
|
||||
- if not _script_within_dir(entry.name, scripts_dir):
|
||||
+ # distlib joins the entry point name onto the scripts directory, so a name
|
||||
+ # with path separators or ``..`` components can resolve elsewhere. The script
|
||||
+ # must resolve to a path strictly inside the scripts directory.
|
||||
+ dest = os.path.join(scripts_dir, entry.name)
|
||||
+ resolves_to_scripts_dir = os.path.abspath(dest) == os.path.abspath(scripts_dir)
|
||||
+ if resolves_to_scripts_dir or not is_within_directory(scripts_dir, dest):
|
||||
raise InstallationError(
|
||||
f"Invalid script entry point name {entry.name!r}: the script "
|
||||
f"would be installed outside the scripts directory ({scripts_dir})."
|
||||
diff --git a/src/pip/_internal/utils/unpacking.py b/src/pip/_internal/utils/unpacking.py
|
||||
index 188f27e67..14b7e846a 100644
|
||||
--- a/src/pip/_internal/utils/unpacking.py
|
||||
+++ b/src/pip/_internal/utils/unpacking.py
|
||||
@@ -77,6 +77,7 @@ def has_leading_dir(paths: Iterable[str]) -> bool:
|
||||
def is_within_directory(directory: str, target: str) -> bool:
|
||||
"""
|
||||
Return true if the absolute path of target is within the directory
|
||||
+ (including when target is equal to the directory).
|
||||
"""
|
||||
abs_directory = os.path.abspath(directory)
|
||||
abs_target = os.path.abspath(target)
|
||||
--
|
||||
2.35.6
|
||||
79
meta/recipes-devtools/python/python3-pip/CVE-2026-8643.patch
Normal file
79
meta/recipes-devtools/python/python3-pip/CVE-2026-8643.patch
Normal file
@@ -0,0 +1,79 @@
|
||||
From fc0f7c683c372d66f2e2d6edc00909cc5f225f67 Mon Sep 17 00:00:00 2001
|
||||
From: Damian Shaw <damian.peter.shaw@gmail.com>
|
||||
Date: Wed, 20 May 2026 15:20:25 -0400
|
||||
Subject: [PATCH] Reject entry point names that escape scripts dir (#14000)
|
||||
|
||||
* Reject entry point names that escape scripts dir
|
||||
|
||||
* NEWS ENTRY
|
||||
|
||||
CVE: CVE-2026-8643
|
||||
Upstream-Status: Backport [https://github.com/pypa/pip/commit/8eb178480bd1a2b223f509fc430796b265158dfb]
|
||||
|
||||
Backport Changes:
|
||||
- Omit tests/unit/test_wheel.py because the pip 24.0 PyPI sdist used by this
|
||||
recipe does not ship the upstream tests directory.
|
||||
|
||||
(cherry picked from commit 8eb178480bd1a2b223f509fc430796b265158dfb)
|
||||
Signed-off-by: Hetvi Thakar <hthakar@cisco.com>
|
||||
---
|
||||
news/14000.bugfix.rst | 2 +
|
||||
src/pip/_internal/operations/install/wheel.py | 26 +++++++-
|
||||
2 files changed, 25 insertions(+), 3 deletions(-)
|
||||
create mode 100644 news/14000.bugfix.rst
|
||||
|
||||
diff --git a/news/14000.bugfix.rst b/news/14000.bugfix.rst
|
||||
new file mode 100644
|
||||
index 000000000..3b86f1b3b
|
||||
--- /dev/null
|
||||
+++ b/news/14000.bugfix.rst
|
||||
@@ -0,0 +1,2 @@
|
||||
+Reject ``console_scripts`` and ``gui_scripts`` entry points whose name would
|
||||
+install a script outside the scripts directory.
|
||||
diff --git a/src/pip/_internal/operations/install/wheel.py b/src/pip/_internal/operations/install/wheel.py
|
||||
index f67180c9e..8a36a66ae 100644
|
||||
--- a/src/pip/_internal/operations/install/wheel.py
|
||||
+++ b/src/pip/_internal/operations/install/wheel.py
|
||||
@@ -409,17 +409,37 @@ class MissingCallableSuffix(InstallationError):
|
||||
)
|
||||
|
||||
|
||||
-def _raise_for_invalid_entrypoint(specification: str) -> None:
|
||||
+def _script_within_dir(name: str, scripts_dir: str) -> bool:
|
||||
+ """Return whether script ``name`` resolves to a path inside the ``scripts_dir``.
|
||||
+
|
||||
+ distlib joins the entry point name onto the scripts directory, so a name
|
||||
+ with path separators or ``..`` components can resolve elsewhere.
|
||||
+ """
|
||||
+ root = os.path.normpath(scripts_dir)
|
||||
+ dest = os.path.normpath(os.path.join(scripts_dir, name))
|
||||
+ return dest.startswith(root + os.sep)
|
||||
+
|
||||
+
|
||||
+def _raise_for_invalid_entrypoint(specification: str, scripts_dir: str) -> None:
|
||||
entry = get_export_entry(specification)
|
||||
- if entry is not None and entry.suffix is None:
|
||||
+ if entry is None:
|
||||
+ return
|
||||
+
|
||||
+ if entry.suffix is None:
|
||||
raise MissingCallableSuffix(str(entry))
|
||||
|
||||
+ if not _script_within_dir(entry.name, scripts_dir):
|
||||
+ raise InstallationError(
|
||||
+ f"Invalid script entry point name {entry.name!r}: the script "
|
||||
+ f"would be installed outside the scripts directory ({scripts_dir})."
|
||||
+ )
|
||||
+
|
||||
|
||||
class PipScriptMaker(ScriptMaker):
|
||||
def make(
|
||||
self, specification: str, options: Optional[Dict[str, Any]] = None
|
||||
) -> List[str]:
|
||||
- _raise_for_invalid_entrypoint(specification)
|
||||
+ _raise_for_invalid_entrypoint(specification, self.target_dir)
|
||||
return super().make(specification, options)
|
||||
|
||||
|
||||
--
|
||||
2.35.6
|
||||
Reference in New Issue
Block a user