forked from pool/python310
121 lines
5.5 KiB
Diff
121 lines
5.5 KiB
Diff
From b99e2bfb8c1b1f61377193d51cf627689ec62606 Mon Sep 17 00:00:00 2001
|
|
From: Stan Ulbrych <89152624+StanFromIreland@users.noreply.github.com>
|
|
Date: Wed, 18 Mar 2026 17:31:01 +0000
|
|
Subject: [PATCH] gh-146121: `pkgutil.get_data()` reject invalid resource
|
|
arguments (GH-146122) (cherry picked from commit
|
|
bcdf231946b1da8bdfbab4c05539bb0cc964a1c7)
|
|
|
|
Co-authored-by: Stan Ulbrych <89152624+StanFromIreland@users.noreply.github.com>
|
|
---
|
|
Doc/library/pkgutil.rst | 25 +++++++++-
|
|
Lib/pkgutil.py | 3 +
|
|
Lib/test/test_pkgutil.py | 19 +++++++
|
|
Misc/NEWS.d/next/Security/2026-03-16-18-07-00.gh-issue-146121.vRbdro.rst | 3 +
|
|
4 files changed, 48 insertions(+), 2 deletions(-)
|
|
create mode 100644 Misc/NEWS.d/next/Security/2026-03-16-18-07-00.gh-issue-146121.vRbdro.rst
|
|
|
|
Index: Python-3.10.20/Doc/library/pkgutil.rst
|
|
===================================================================
|
|
--- Python-3.10.20.orig/Doc/library/pkgutil.rst 2026-03-03 01:49:35.000000000 +0100
|
|
+++ Python-3.10.20/Doc/library/pkgutil.rst 2026-04-07 23:51:43.349243333 +0200
|
|
@@ -210,24 +210,45 @@
|
|
:meth:`get_data <importlib.abc.ResourceLoader.get_data>` API. The
|
|
*package* argument should be the name of a package, in standard module format
|
|
(``foo.bar``). The *resource* argument should be in the form of a relative
|
|
- filename, using ``/`` as the path separator. The parent directory name
|
|
- ``..`` is not allowed, and nor is a rooted name (starting with a ``/``).
|
|
+ filename, using ``/`` as the path separator.
|
|
|
|
The function returns a binary string that is the contents of the specified
|
|
resource.
|
|
|
|
+ This function uses the :term:`loader` method
|
|
+ :func:`~importlib.abc.FileLoader.get_data`
|
|
+ to support modules installed in the filesystem, but also in zip files,
|
|
+ databases, or elsewhere.
|
|
+
|
|
For packages located in the filesystem, which have already been imported,
|
|
this is the rough equivalent of::
|
|
|
|
d = os.path.dirname(sys.modules[package].__file__)
|
|
data = open(os.path.join(d, resource), 'rb').read()
|
|
|
|
+ Like the :func:`open` function, :func:`!get_data` can follow parent
|
|
+ directories (``../``) and absolute paths (starting with ``/`` or ``C:/``,
|
|
+ for example).
|
|
+
|
|
+ .. warning::
|
|
+
|
|
+ This function is intended for trusted input.
|
|
+ It does not verify that *resource* "belongs" to *package*.
|
|
+
|
|
+ If you use a user-provided *resource* path, consider verifying it.
|
|
+ For example, require an alphanumeric filename with a known extension, or
|
|
+ install and check a list of known resources.
|
|
+
|
|
If the package cannot be located or loaded, or it uses a :term:`loader`
|
|
which does not support :meth:`get_data <importlib.abc.ResourceLoader.get_data>`,
|
|
then ``None`` is returned. In particular, the :term:`loader` for
|
|
:term:`namespace packages <namespace package>` does not support
|
|
:meth:`get_data <importlib.abc.ResourceLoader.get_data>`.
|
|
|
|
+ .. seealso::
|
|
+
|
|
+ The :mod:`importlib.resources` module provides structured access to
|
|
+ module resources.
|
|
|
|
.. function:: resolve_name(name)
|
|
|
|
Index: Python-3.10.20/Lib/pkgutil.py
|
|
===================================================================
|
|
--- Python-3.10.20.orig/Lib/pkgutil.py 2026-04-07 23:43:19.182316187 +0200
|
|
+++ Python-3.10.20/Lib/pkgutil.py 2026-04-07 23:43:24.721674221 +0200
|
|
@@ -634,6 +634,9 @@
|
|
# signature - an os.path format "filename" starting with the dirname of
|
|
# the package's __file__
|
|
parts = resource.split('/')
|
|
+ if os.path.isabs(resource) or '..' in parts:
|
|
+ raise ValueError("resource must be a relative path with no "
|
|
+ "parent directory components")
|
|
parts.insert(0, os.path.dirname(mod.__file__))
|
|
resource_name = os.path.join(*parts)
|
|
return loader.get_data(resource_name)
|
|
Index: Python-3.10.20/Lib/test/test_pkgutil.py
|
|
===================================================================
|
|
--- Python-3.10.20.orig/Lib/test/test_pkgutil.py 2026-04-07 23:43:20.574049381 +0200
|
|
+++ Python-3.10.20/Lib/test/test_pkgutil.py 2026-04-07 23:43:24.721964087 +0200
|
|
@@ -56,6 +56,25 @@
|
|
|
|
del sys.modules[pkg]
|
|
|
|
+ def test_getdata_path_traversal(self):
|
|
+ pkg = 'test_getdata_traversal'
|
|
+
|
|
+ # Make a package with some resources
|
|
+ package_dir = os.path.join(self.dirname, pkg)
|
|
+ os.mkdir(package_dir)
|
|
+ # Empty init.py
|
|
+ f = open(os.path.join(package_dir, '__init__.py'), "wb")
|
|
+ f.close()
|
|
+
|
|
+ with self.assertRaises(ValueError):
|
|
+ pkgutil.get_data(pkg, '../../../etc/passwd')
|
|
+ with self.assertRaises(ValueError):
|
|
+ pkgutil.get_data(pkg, 'sub/../../../etc/passwd')
|
|
+ with self.assertRaises(ValueError):
|
|
+ pkgutil.get_data(pkg, os.path.abspath('/etc/passwd'))
|
|
+
|
|
+ del sys.modules[pkg]
|
|
+
|
|
def test_getdata_zipfile(self):
|
|
zip = 'test_getdata_zipfile.zip'
|
|
pkg = 'test_getdata_zipfile'
|
|
Index: Python-3.10.20/Misc/NEWS.d/next/Security/2026-03-16-18-07-00.gh-issue-146121.vRbdro.rst
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ Python-3.10.20/Misc/NEWS.d/next/Security/2026-03-16-18-07-00.gh-issue-146121.vRbdro.rst 2026-04-07 23:43:24.722230889 +0200
|
|
@@ -0,0 +1,3 @@
|
|
+:func:`pkgutil.get_data` now raises rejects *resource* arguments containing the
|
|
+parent directory components or that is an absolute path.
|
|
+This addresses :cve:`2026-3479`.
|