* [PATCH] [OE-core] [meta-openembedded] python3-django: fix CVE-2021-3281
@ 2021-02-18 20:47 Stefan Ghinea
0 siblings, 0 replies; only message in thread
From: Stefan Ghinea @ 2021-02-18 20:47 UTC (permalink / raw)
To: openembedded-core
In Django 2.2 before 2.2.18, 3.0 before 3.0.12, and 3.1 before 3.1.6, the
django.utils.archive.extract method (used by startapp --template and
startproject --template) allows directory traversal via an archive with
absolute paths or relative paths with dot segments.
References:
https://nvd.nist.gov/vuln/detail/CVE-2021-3281
Upstream patches:
https://github.com/django/django/commit/21e7622dec1f8612c85c2fc37fe8efbfd3311e37
https://github.com/django/django/commit/02e6592835b4559909aa3aaaf67988fef435f624
Signed-off-by: Stefan Ghinea <stefan.ghinea@windriver.com>
---
.../python3-django-2.2.16/CVE-2021-3281.patch | 138 ++++++++++++++++++
.../python3-django-3.1.1/CVE-2021-3281.patch | 135 +++++++++++++++++
.../python/python3-django_2.2.16.bb | 2 +
.../python/python3-django_3.1.1.bb | 3 +
4 files changed, 278 insertions(+)
create mode 100644 meta-python/recipes-devtools/python/python3-django-2.2.16/CVE-2021-3281.patch
create mode 100644 meta-python/recipes-devtools/python/python3-django-3.1.1/CVE-2021-3281.patch
diff --git a/meta-python/recipes-devtools/python/python3-django-2.2.16/CVE-2021-3281.patch b/meta-python/recipes-devtools/python/python3-django-2.2.16/CVE-2021-3281.patch
new file mode 100644
index 000000000..36591ce6f
--- /dev/null
+++ b/meta-python/recipes-devtools/python/python3-django-2.2.16/CVE-2021-3281.patch
@@ -0,0 +1,138 @@
+From 21e7622dec1f8612c85c2fc37fe8efbfd3311e37 Mon Sep 17 00:00:00 2001
+From: Mariusz Felisiak <felisiak.mariusz@gmail.com>
+Date: Fri, 22 Jan 2021 12:23:18 +0100
+Subject: [PATCH] Fixed CVE-2021-3281 -- Fixed potential directory-traversal
+ via archive.extract().
+
+Thanks Florian Apolloner, Shai Berger, and Simon Charette for reviews.
+
+Thanks Wang Baohua for the report.
+
+Backport of 05413afa8c18cdb978fcdf470e09f7a12b234a23 from master.
+
+Upstream-Status: Backport
+CVE: CVE-2021-3281
+
+Reference to upstream patch:
+[https://github.com/django/django/commit/21e7622dec1f8612c85c2fc37fe8efbfd3311e37]
+
+[SG: Adapted stable/2.2.x patch for 2.2.16]
+Signed-off-by: Stefan Ghinea <stefan.ghinea@windriver.com>
+---
+ django/utils/archive.py | 17 ++++++++++++++---
+ docs/releases/2.2.16.txt | 10 ++++++++++
+ tests/utils_tests/test_archive.py | 21 +++++++++++++++++++++
+ 3 files changed, 45 insertions(+), 3 deletions(-)
+
+diff --git a/django/utils/archive.py b/django/utils/archive.py
+index 5b9998f..f2f153a 100644
+--- a/django/utils/archive.py
++++ b/django/utils/archive.py
+@@ -27,6 +27,8 @@ import stat
+ import tarfile
+ import zipfile
+
++from django.core.exceptions import SuspiciousOperation
++
+
+ class ArchiveException(Exception):
+ """
+@@ -133,6 +135,13 @@ class BaseArchive:
+ return False
+ return True
+
++ def target_filename(self, to_path, name):
++ target_path = os.path.abspath(to_path)
++ filename = os.path.abspath(os.path.join(target_path, name))
++ if not filename.startswith(target_path):
++ raise SuspiciousOperation("Archive contains invalid path: '%s'" % name)
++ return filename
++
+ def extract(self):
+ raise NotImplementedError('subclasses of BaseArchive must provide an extract() method')
+
+@@ -155,7 +164,7 @@ class TarArchive(BaseArchive):
+ name = member.name
+ if leading:
+ name = self.split_leading_dir(name)[1]
+- filename = os.path.join(to_path, name)
++ filename = self.target_filename(to_path, name)
+ if member.isdir():
+ if filename and not os.path.exists(filename):
+ os.makedirs(filename)
+@@ -198,11 +207,13 @@ class ZipArchive(BaseArchive):
+ info = self._archive.getinfo(name)
+ if leading:
+ name = self.split_leading_dir(name)[1]
+- filename = os.path.join(to_path, name)
++ if not name:
++ continue
++ filename = self.target_filename(to_path, name)
+ dirname = os.path.dirname(filename)
+ if dirname and not os.path.exists(dirname):
+ os.makedirs(dirname)
+- if filename.endswith(('/', '\\')):
++ if name.endswith(('/', '\\')):
+ # A directory
+ if not os.path.exists(filename):
+ os.makedirs(filename)
+diff --git a/docs/releases/2.2.16.txt b/docs/releases/2.2.16.txt
+index 31231fb..94682a1 100644
+--- a/docs/releases/2.2.16.txt
++++ b/docs/releases/2.2.16.txt
+@@ -4,6 +4,16 @@ Django 2.2.16 release notes
+
+ *September 1, 2020*
+
++Backported from Django 2.2.18 a fix for a security issue.
++
++CVE-2021-3281: Potential directory-traversal via ``archive.extract()``
++======================================================================
++
++The ``django.utils.archive.extract()`` function, used by
++:option:`startapp --template` and :option:`startproject --template`, allowed
++directory-traversal via an archive with absolute paths or relative paths with
++dot segments.
++
+ Django 2.2.16 fixes two security issues and two data loss bugs in 2.2.15.
+
+ CVE-2020-24583: Incorrect permissions on intermediate-level directories on Python 3.7+
+diff --git a/tests/utils_tests/test_archive.py b/tests/utils_tests/test_archive.py
+index d58d211..ed7908d 100644
+--- a/tests/utils_tests/test_archive.py
++++ b/tests/utils_tests/test_archive.py
+@@ -5,6 +5,8 @@ import sys
+ import tempfile
+ import unittest
+
++from django.core.exceptions import SuspiciousOperation
++from django.test import SimpleTestCase
+ from django.utils.archive import Archive, extract
+
+ TEST_DIR = os.path.join(os.path.dirname(__file__), 'archives')
+@@ -87,3 +89,22 @@ class TestGzipTar(ArchiveTester, unittest.TestCase):
+
+ class TestBzip2Tar(ArchiveTester, unittest.TestCase):
+ archive = 'foobar.tar.bz2'
++
++
++class TestArchiveInvalid(SimpleTestCase):
++ def test_extract_function_traversal(self):
++ archives_dir = os.path.join(os.path.dirname(__file__), 'traversal_archives')
++ tests = [
++ ('traversal.tar', '..'),
++ ('traversal_absolute.tar', '/tmp/evil.py'),
++ ]
++ if sys.platform == 'win32':
++ tests += [
++ ('traversal_disk_win.tar', 'd:evil.py'),
++ ('traversal_disk_win.zip', 'd:evil.py'),
++ ]
++ msg = "Archive contains invalid path: '%s'"
++ for entry, invalid_path in tests:
++ with self.subTest(entry), tempfile.TemporaryDirectory() as tmpdir:
++ with self.assertRaisesMessage(SuspiciousOperation, msg % invalid_path):
++ extract(os.path.join(archives_dir, entry), tmpdir)
+--
+2.17.1
+
diff --git a/meta-python/recipes-devtools/python/python3-django-3.1.1/CVE-2021-3281.patch b/meta-python/recipes-devtools/python/python3-django-3.1.1/CVE-2021-3281.patch
new file mode 100644
index 000000000..08b87a45a
--- /dev/null
+++ b/meta-python/recipes-devtools/python/python3-django-3.1.1/CVE-2021-3281.patch
@@ -0,0 +1,135 @@
+From 02e6592835b4559909aa3aaaf67988fef435f624 Mon Sep 17 00:00:00 2001
+From: Mariusz Felisiak <felisiak.mariusz@gmail.com>
+Date: Fri, 22 Jan 2021 12:23:18 +0100
+Subject: [PATCH] Fixed CVE-2021-3281 -- Fixed potential directory-traversal
+ via archive.extract().
+
+Thanks Florian Apolloner, Shai Berger, and Simon Charette for reviews.
+
+Thanks Wang Baohua for the report.
+
+Backport of 05413afa8c18cdb978fcdf470e09f7a12b234a23 from master.
+
+Upstream-Status: Backport
+CVE: CVE-2021-3281
+
+Reference to upstream patch:
+[https://github.com/django/django/commit/02e6592835b4559909aa3aaaf67988fef435f624]
+
+[SG: Adapted stable/3.1.x patch for 3.1.1]
+Signed-off-by: Stefan Ghinea <stefan.ghinea@windriver.com>
+---
+ django/utils/archive.py | 17 ++++++++++++++---
+ docs/releases/3.1.1.txt | 10 ++++++++++
+ tests/utils_tests/test_archive.py | 21 +++++++++++++++++++++
+ 3 files changed, 45 insertions(+), 3 deletions(-)
+
+diff --git a/django/utils/archive.py b/django/utils/archive.py
+index 235809f..d5a0cf0 100644
+--- a/django/utils/archive.py
++++ b/django/utils/archive.py
+@@ -27,6 +27,8 @@ import stat
+ import tarfile
+ import zipfile
+
++from django.core.exceptions import SuspiciousOperation
++
+
+ class ArchiveException(Exception):
+ """
+@@ -133,6 +135,13 @@ class BaseArchive:
+ return False
+ return True
+
++ def target_filename(self, to_path, name):
++ target_path = os.path.abspath(to_path)
++ filename = os.path.abspath(os.path.join(target_path, name))
++ if not filename.startswith(target_path):
++ raise SuspiciousOperation("Archive contains invalid path: '%s'" % name)
++ return filename
++
+ def extract(self):
+ raise NotImplementedError('subclasses of BaseArchive must provide an extract() method')
+
+@@ -155,7 +164,7 @@ class TarArchive(BaseArchive):
+ name = member.name
+ if leading:
+ name = self.split_leading_dir(name)[1]
+- filename = os.path.join(to_path, name)
++ filename = self.target_filename(to_path, name)
+ if member.isdir():
+ if filename:
+ os.makedirs(filename, exist_ok=True)
+@@ -198,8 +207,10 @@ class ZipArchive(BaseArchive):
+ info = self._archive.getinfo(name)
+ if leading:
+ name = self.split_leading_dir(name)[1]
+- filename = os.path.join(to_path, name)
+- if filename.endswith(('/', '\\')):
++ if not name:
++ continue
++ filename = self.target_filename(to_path, name)
++ if name.endswith(('/', '\\')):
+ # A directory
+ os.makedirs(filename, exist_ok=True)
+ else:
+diff --git a/docs/releases/3.1.1.txt b/docs/releases/3.1.1.txt
+index 0a702e9..ed23464 100644
+--- a/docs/releases/3.1.1.txt
++++ b/docs/releases/3.1.1.txt
+@@ -4,6 +4,16 @@ Django 3.1.1 release notes
+
+ *September 1, 2020*
+
++Backported from Django 3.1.6 a fix for a security issue.
++
++CVE-2021-3281: Potential directory-traversal via ``archive.extract()``
++======================================================================
++
++The ``django.utils.archive.extract()`` function, used by
++:option:`startapp --template` and :option:`startproject --template`, allowed
++directory-traversal via an archive with absolute paths or relative paths with
++dot segments.
++
+ Django 3.1.1 fixes two security issues and several bugs in 3.1.
+
+ CVE-2020-24583: Incorrect permissions on intermediate-level directories on Python 3.7+
+diff --git a/tests/utils_tests/test_archive.py b/tests/utils_tests/test_archive.py
+index dc7c4b4..8fdf3ec 100644
+--- a/tests/utils_tests/test_archive.py
++++ b/tests/utils_tests/test_archive.py
+@@ -4,6 +4,8 @@ import sys
+ import tempfile
+ import unittest
+
++from django.core.exceptions import SuspiciousOperation
++from django.test import SimpleTestCase
+ from django.utils import archive
+
+
+@@ -45,3 +47,22 @@ class TestArchive(unittest.TestCase):
+ # A file is readable even if permission data is missing.
+ filepath = os.path.join(tmpdir, 'no_permissions')
+ self.assertEqual(os.stat(filepath).st_mode & mask, 0o666 & ~umask)
++
++
++class TestArchiveInvalid(SimpleTestCase):
++ def test_extract_function_traversal(self):
++ archives_dir = os.path.join(os.path.dirname(__file__), 'traversal_archives')
++ tests = [
++ ('traversal.tar', '..'),
++ ('traversal_absolute.tar', '/tmp/evil.py'),
++ ]
++ if sys.platform == 'win32':
++ tests += [
++ ('traversal_disk_win.tar', 'd:evil.py'),
++ ('traversal_disk_win.zip', 'd:evil.py'),
++ ]
++ msg = "Archive contains invalid path: '%s'"
++ for entry, invalid_path in tests:
++ with self.subTest(entry), tempfile.TemporaryDirectory() as tmpdir:
++ with self.assertRaisesMessage(SuspiciousOperation, msg % invalid_path):
++ archive.extract(os.path.join(archives_dir, entry), tmpdir)
+--
+2.17.1
+
diff --git a/meta-python/recipes-devtools/python/python3-django_2.2.16.bb b/meta-python/recipes-devtools/python/python3-django_2.2.16.bb
index 0715abbd4..2ad14f83e 100644
--- a/meta-python/recipes-devtools/python/python3-django_2.2.16.bb
+++ b/meta-python/recipes-devtools/python/python3-django_2.2.16.bb
@@ -7,3 +7,5 @@ SRC_URI[sha256sum] = "62cf45e5ee425c52e411c0742e641a6588b7e8af0d2c274a27940931b2
RDEPENDS_${PN} += "\
${PYTHON_PN}-sqlparse \
"
+SRC_URI += "file://CVE-2021-3281.patch \
+"
diff --git a/meta-python/recipes-devtools/python/python3-django_3.1.1.bb b/meta-python/recipes-devtools/python/python3-django_3.1.1.bb
index ed6513d0c..bd7261355 100644
--- a/meta-python/recipes-devtools/python/python3-django_3.1.1.bb
+++ b/meta-python/recipes-devtools/python/python3-django_3.1.1.bb
@@ -8,6 +8,9 @@ RDEPENDS_${PN} += "\
${PYTHON_PN}-sqlparse \
"
+SRC_URI += "file://CVE-2021-3281.patch \
+"
+
# Set DEFAULT_PREFERENCE so that the LTS version of django is built by
# default. To build the 3.x branch,
# PREFERRED_VERSION_python3-django = "3.1.1" can be added to local.conf
--
2.17.1
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2021-02-18 20:47 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-02-18 20:47 [PATCH] [OE-core] [meta-openembedded] python3-django: fix CVE-2021-3281 Stefan Ghinea
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.