mirror of
https://gitlab.com/buildroot.org/buildroot.git
synced 2026-10-01 06:21:56 -09:00
package/python3: add upstream security patch for CVE-2026-8328
https://mail.python.org/archives/list/security-announce@python.org/thread/ITF2BAPBQEPYK3LDMPRSY435JGNHYNDP/ Signed-off-by: Bernd Kuhls <bernd@kuhls.net> Signed-off-by: Julien Olivain <ju.o@free.fr>
This commit is contained in:
committed by
Julien Olivain
parent
67ec0e9c20
commit
d4be78ccb5
@@ -0,0 +1,123 @@
|
|||||||
|
From 7d95a1dc7382b55cba7fdd6a110336077584a4f0 Mon Sep 17 00:00:00 2001
|
||||||
|
From: "Miss Islington (bot)"
|
||||||
|
<31488909+miss-islington@users.noreply.github.com>
|
||||||
|
Date: Wed, 13 May 2026 19:59:11 +0200
|
||||||
|
Subject: [PATCH] [3.14] gh-87451: Apply CVE-2021-4189 PASV fix to
|
||||||
|
ftplib.ftpcp() (GH-149648) (#149793)
|
||||||
|
|
||||||
|
gh-87451: Apply CVE-2021-4189 PASV fix to ftplib.ftpcp() (GH-149648)
|
||||||
|
|
||||||
|
ftpcp() called parse227() directly and passed the source server's
|
||||||
|
self-reported PASV IPv4 address to the target server's PORT command,
|
||||||
|
bypassing the CVE-2021-4189 fix that was applied only to FTP.makepasv().
|
||||||
|
A malicious source FTP server could use this to redirect the target
|
||||||
|
server's data connection to an arbitrary host:port (SSRF).
|
||||||
|
|
||||||
|
ftpcp() now uses the source server's actual peer address, honoring the
|
||||||
|
existing trust_server_pasv_ipv4_address opt-out, the same as makepasv().
|
||||||
|
|
||||||
|
Thanks to Qi Ding at Aurascape AI for the report. (GHSA-w8c5-q2xf-gf7c)
|
||||||
|
(cherry picked from commit eac4fe3b2c77693790a5ef7dfab127c1fee81bf9)
|
||||||
|
|
||||||
|
Co-authored-by: Gregory P. Smith <68491+gpshead@users.noreply.github.com>
|
||||||
|
Upstream: https://github.com/python/cpython/commit/7d95a1dc7382b55cba7fdd6a110336077584a4f0
|
||||||
|
CVE: CVE-2026-8328
|
||||||
|
Signed-off-by: Bernd Kuhls <bernd@kuhls.net>
|
||||||
|
---
|
||||||
|
Lib/ftplib.py | 11 +++++-
|
||||||
|
Lib/test/test_ftplib.py | 36 ++++++++++++++++++-
|
||||||
|
...6-05-10-18-05-32.gh-issue-87451.XkKB6M.rst | 6 ++++
|
||||||
|
3 files changed, 51 insertions(+), 2 deletions(-)
|
||||||
|
create mode 100644 Misc/NEWS.d/next/Security/2026-05-10-18-05-32.gh-issue-87451.XkKB6M.rst
|
||||||
|
|
||||||
|
diff --git a/Lib/ftplib.py b/Lib/ftplib.py
|
||||||
|
index 50771e8c17c..73882a38dce 100644
|
||||||
|
--- a/Lib/ftplib.py
|
||||||
|
+++ b/Lib/ftplib.py
|
||||||
|
@@ -883,7 +883,16 @@ def ftpcp(source, sourcename, target, targetname = '', type = 'I'):
|
||||||
|
type = 'TYPE ' + type
|
||||||
|
source.voidcmd(type)
|
||||||
|
target.voidcmd(type)
|
||||||
|
- sourcehost, sourceport = parse227(source.sendcmd('PASV'))
|
||||||
|
+ # Don't trust the IPv4 address the source server advertises in its PASV
|
||||||
|
+ # reply: a malicious source could otherwise point the target's data
|
||||||
|
+ # connection at an arbitrary host (SSRF). A caller that needs the old
|
||||||
|
+ # behavior can set trust_server_pasv_ipv4_address on the source FTP
|
||||||
|
+ # object. See FTP.makepasv(), which applies the same rule.
|
||||||
|
+ untrusted_host, sourceport = parse227(source.sendcmd('PASV'))
|
||||||
|
+ if source.trust_server_pasv_ipv4_address:
|
||||||
|
+ sourcehost = untrusted_host
|
||||||
|
+ else:
|
||||||
|
+ sourcehost = source.sock.getpeername()[0]
|
||||||
|
target.sendport(sourcehost, sourceport)
|
||||||
|
# RFC 959: the user must "listen" [...] BEFORE sending the
|
||||||
|
# transfer request.
|
||||||
|
diff --git a/Lib/test/test_ftplib.py b/Lib/test/test_ftplib.py
|
||||||
|
index c864d401f9e..f1eff9430f7 100644
|
||||||
|
--- a/Lib/test/test_ftplib.py
|
||||||
|
+++ b/Lib/test/test_ftplib.py
|
||||||
|
@@ -16,7 +16,7 @@
|
||||||
|
except ImportError:
|
||||||
|
ssl = None
|
||||||
|
|
||||||
|
-from unittest import TestCase, skipUnless
|
||||||
|
+from unittest import mock, TestCase, skipUnless
|
||||||
|
from test import support
|
||||||
|
from test.support import requires_subprocess
|
||||||
|
from test.support import threading_helper
|
||||||
|
@@ -1145,6 +1145,40 @@ def testTimeoutDirectAccess(self):
|
||||||
|
ftp.close()
|
||||||
|
|
||||||
|
|
||||||
|
+class TestFtpcpSecurity(TestCase):
|
||||||
|
+ """ftpcp() must not trust the host a source server advertises in PASV.
|
||||||
|
+
|
||||||
|
+ A malicious source server can otherwise redirect the target server's
|
||||||
|
+ data connection to an arbitrary host:port (SSRF), so ftpcp() uses the
|
||||||
|
+ source server's actual peer address instead, the same as FTP.makepasv().
|
||||||
|
+ """
|
||||||
|
+
|
||||||
|
+ def _make_pair(self, *, advertised_host, real_host, trust=False):
|
||||||
|
+ source = mock.Mock(spec=ftplib.FTP)
|
||||||
|
+ source.trust_server_pasv_ipv4_address = trust
|
||||||
|
+ source.sock.getpeername.return_value = (real_host, 21)
|
||||||
|
+ # PASV replies give the host as comma-separated octets, not dotted.
|
||||||
|
+ advertised = advertised_host.replace('.', ',')
|
||||||
|
+ source.sendcmd.side_effect = lambda cmd: (
|
||||||
|
+ f'227 Entering Passive Mode ({advertised},1,2).'
|
||||||
|
+ if cmd == 'PASV' else '150 ok')
|
||||||
|
+ target = mock.Mock(spec=ftplib.FTP)
|
||||||
|
+ target.sendcmd.return_value = '150 ok'
|
||||||
|
+ return source, target
|
||||||
|
+
|
||||||
|
+ def test_ftpcp_ignores_untrusted_pasv_host(self):
|
||||||
|
+ source, target = self._make_pair(advertised_host='10.0.0.5',
|
||||||
|
+ real_host='198.51.100.7')
|
||||||
|
+ ftplib.ftpcp(source, 'a', target, 'b')
|
||||||
|
+ target.sendport.assert_called_once_with('198.51.100.7', 258)
|
||||||
|
+
|
||||||
|
+ def test_ftpcp_trust_server_pasv_ipv4_address(self):
|
||||||
|
+ source, target = self._make_pair(advertised_host='10.0.0.5',
|
||||||
|
+ real_host='198.51.100.7', trust=True)
|
||||||
|
+ ftplib.ftpcp(source, 'a', target, 'b')
|
||||||
|
+ target.sendport.assert_called_once_with('10.0.0.5', 258)
|
||||||
|
+
|
||||||
|
+
|
||||||
|
class MiscTestCase(TestCase):
|
||||||
|
def test__all__(self):
|
||||||
|
not_exported = {
|
||||||
|
diff --git a/Misc/NEWS.d/next/Security/2026-05-10-18-05-32.gh-issue-87451.XkKB6M.rst b/Misc/NEWS.d/next/Security/2026-05-10-18-05-32.gh-issue-87451.XkKB6M.rst
|
||||||
|
new file mode 100644
|
||||||
|
index 00000000000..21a79c3e0e7
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/Misc/NEWS.d/next/Security/2026-05-10-18-05-32.gh-issue-87451.XkKB6M.rst
|
||||||
|
@@ -0,0 +1,6 @@
|
||||||
|
+The :mod:`ftplib` module's undocumented ``ftpcp`` function no longer trusts
|
||||||
|
+the IPv4 address value returned from the source server in response to the
|
||||||
|
+``PASV`` command by default, completing the fix for CVE-2021-4189. As with
|
||||||
|
+:class:`ftplib.FTP`, the former behavior can be re-enabled by setting the
|
||||||
|
+``trust_server_pasv_ipv4_address`` attribute on the source :class:`ftplib.FTP`
|
||||||
|
+instance to ``True``. Thanks to Qi Deng at Aurascape AI for the report.
|
||||||
|
--
|
||||||
|
2.47.3
|
||||||
|
|
||||||
@@ -19,6 +19,9 @@ PYTHON3_IGNORE_CVES += CVE-2026-3276
|
|||||||
# 0012-3.14-gh-149486-tarfile.data_filter-validate-written-.patch
|
# 0012-3.14-gh-149486-tarfile.data_filter-validate-written-.patch
|
||||||
PYTHON3_IGNORE_CVES += CVE-2026-7774
|
PYTHON3_IGNORE_CVES += CVE-2026-7774
|
||||||
|
|
||||||
|
# 0013-3.14-gh-87451-Apply-CVE-2021-4189-PASV-fix-to-ftplib.patch
|
||||||
|
PYTHON3_IGNORE_CVES += CVE-2026-8328
|
||||||
|
|
||||||
# This host Python is installed in $(HOST_DIR), as it is needed when
|
# This host Python is installed in $(HOST_DIR), as it is needed when
|
||||||
# cross-compiling third-party Python modules.
|
# cross-compiling third-party Python modules.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user