diff --git a/debian/changelog b/debian/changelog index b1c56f7c5..d6472a04e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +python-django (1:1.10.7-2+deb9u4) stretch-security; urgency=high + + * CVE-2019-3498: Fix a content spoofing vulnerability in the default + 404 page. (Closes: #918230) + + -- Chris Lamb Sat, 05 Jan 2019 21:36:27 +0100 + python-django (1:1.10.7-2+deb9u3) stretch; urgency=medium * Default to supporting Spatialite >= 4.2. (Closes: #910240) diff --git a/debian/patches/0017-CVE-2019-3498.patch b/debian/patches/0017-CVE-2019-3498.patch new file mode 100644 index 000000000..ea647e964 --- /dev/null +++ b/debian/patches/0017-CVE-2019-3498.patch @@ -0,0 +1,401 @@ +From: Tom Hacohen +Date: Fri, 4 Jan 2019 02:21:55 +0000 +Subject: Fixed #30070, + CVE-2019-3498 -- Fixed content spoofing possiblity in the default 404 page. + +Co-Authored-By: Tim Graham +Backport of 1ecc0a395be721e987e8e9fdfadde952b6dee1c7 from master. +--- + ...0006-Default-to-supporting-Spatialite-4.2.patch | 4 +-- + debian/patches/0013-CVE-2018-7536.patch | 6 ++-- + debian/patches/0015-CVE-2018-14574.patch | 2 +- + .../patches/02_disable-sources-in-sphinxdoc.diff | 5 ++-- + .../06_use_debian_geoip_database_as_default.diff | 3 +- + debian/patches/fix-migration-fake-initial-1.patch | 20 ++++++++++---- + debian/patches/fix-migration-fake-initial-2.patch | 32 ++++++++++++++++------ + .../fix-test-middleware-classes-headers.patch | 7 ++--- + debian/patches/series | 1 + + django/views/defaults.py | 8 ++++-- + tests/handlers/tests.py | 12 +++++--- + 11 files changed, 65 insertions(+), 35 deletions(-) + +diff --git a/debian/patches/0006-Default-to-supporting-Spatialite-4.2.patch b/debian/patches/0006-Default-to-supporting-Spatialite-4.2.patch +index 6c92929..41e6f79 100644 +--- a/debian/patches/0006-Default-to-supporting-Spatialite-4.2.patch ++++ b/debian/patches/0006-Default-to-supporting-Spatialite-4.2.patch +@@ -14,10 +14,10 @@ See, for example: + 1 file changed, 1 insertion(+), 1 deletion(-) + + diff --git a/django/contrib/gis/db/backends/spatialite/base.py b/django/contrib/gis/db/backends/spatialite/base.py +-index 1f03868..6d0d631 100644 ++index 44514a8..a26270b 100644 + --- a/django/contrib/gis/db/backends/spatialite/base.py + +++ b/django/contrib/gis/db/backends/spatialite/base.py +-@@ -35,7 +35,7 @@ class DatabaseWrapper(SQLiteDatabaseWrapper): ++@@ -30,7 +30,7 @@ class DatabaseWrapper(SQLiteDatabaseWrapper): + # cannot be found by `ctypes.util.find_library`), then it may be set + # manually in the settings via the `SPATIALITE_LIBRARY_PATH` setting. + self.spatialite_lib = getattr(settings, 'SPATIALITE_LIBRARY_PATH', +diff --git a/debian/patches/0013-CVE-2018-7536.patch b/debian/patches/0013-CVE-2018-7536.patch +index 5b1be8f..e54ae4f 100644 +--- a/debian/patches/0013-CVE-2018-7536.patch ++++ b/debian/patches/0013-CVE-2018-7536.patch +@@ -5,8 +5,8 @@ Subject: Fix CVE-2018-7536 -- DOS in urlize + This is a security fix. + --- + django/utils/html.py | 33 +++++++++++++++++++++------------ +- tests/utils_tests/test_html.py | 9 +++++++++ +- 2 files changed, 30 insertions(+), 12 deletions(-) ++ tests/utils_tests/test_html.py | 8 ++++++++ ++ 2 files changed, 29 insertions(+), 12 deletions(-) + + diff --git a/django/utils/html.py b/django/utils/html.py + index a5cb56e..5a9f735 100644 +@@ -81,7 +81,7 @@ index a5cb56e..5a9f735 100644 + try: + domain = domain.encode('idna').decode('ascii') + diff --git a/tests/utils_tests/test_html.py b/tests/utils_tests/test_html.py +-index 20de851..9f76d48 100644 ++index 20de851..8b683c1 100644 + --- a/tests/utils_tests/test_html.py + +++ b/tests/utils_tests/test_html.py + @@ -231,3 +231,11 @@ class TestUtilsHtml(SimpleTestCase): +diff --git a/debian/patches/0015-CVE-2018-14574.patch b/debian/patches/0015-CVE-2018-14574.patch +index c8bf439..2996c0a 100644 +--- a/debian/patches/0015-CVE-2018-14574.patch ++++ b/debian/patches/0015-CVE-2018-14574.patch +@@ -27,7 +27,7 @@ Backported by Chris Lamb from: + 6 files changed, 49 insertions(+), 4 deletions(-) + + diff --git a/django/middleware/common.py b/django/middleware/common.py +-index 4cec6f0..4ac5e01 100644 ++index 4cec6f0..ca35bd4 100644 + --- a/django/middleware/common.py + +++ b/django/middleware/common.py + @@ -9,6 +9,7 @@ from django.urls import is_valid_path +diff --git a/debian/patches/02_disable-sources-in-sphinxdoc.diff b/debian/patches/02_disable-sources-in-sphinxdoc.diff +index bcb214f..f2619d4 100644 +--- a/debian/patches/02_disable-sources-in-sphinxdoc.diff ++++ b/debian/patches/02_disable-sources-in-sphinxdoc.diff +@@ -1,5 +1,4 @@ +-From fbe85f8899cacc79be7864d853e80899288d3e4c Mon Sep 17 00:00:00 2001 +-From: =?UTF-8?q?Rapha=C3=ABl=20Hertzog?= ++From: =?utf-8?q?Rapha=C3=ABl_Hertzog?= + Date: Sun, 11 Oct 2015 11:43:19 +1100 + Subject: Disable creation of _sources directory by Sphinx + +@@ -16,7 +15,7 @@ Patch-Name: 02_disable-sources-in-sphinxdoc.diff + 1 file changed, 4 insertions(+), 1 deletion(-) + + diff --git a/docs/conf.py b/docs/conf.py +-index 5f57ce57e..5b1fab2fd 100644 ++index 5f57ce5..5b1fab2 100644 + --- a/docs/conf.py + +++ b/docs/conf.py + @@ -212,7 +212,10 @@ html_additional_pages = {} +diff --git a/debian/patches/06_use_debian_geoip_database_as_default.diff b/debian/patches/06_use_debian_geoip_database_as_default.diff +index 16faff7..ac82e69 100644 +--- a/debian/patches/06_use_debian_geoip_database_as_default.diff ++++ b/debian/patches/06_use_debian_geoip_database_as_default.diff +@@ -1,4 +1,3 @@ +-From 0e464e28dd41c3a8d8fc0f3317650ec4e029b8c5 Mon Sep 17 00:00:00 2001 + From: Tapio Rantala + Date: Sun, 11 Oct 2015 11:43:20 +1100 + Subject: Use Debian GeoIP database path as default +@@ -16,7 +15,7 @@ Patch-Name: 06_use_debian_geoip_database_as_default.diff + 1 file changed, 10 insertions(+), 9 deletions(-) + + diff --git a/django/contrib/gis/geoip/base.py b/django/contrib/gis/geoip/base.py +-index d40ae7e9a..1e33033b8 100644 ++index d40ae7e..1e33033 100644 + --- a/django/contrib/gis/geoip/base.py + +++ b/django/contrib/gis/geoip/base.py + @@ -68,7 +68,8 @@ class GeoIP(object): +diff --git a/debian/patches/fix-migration-fake-initial-1.patch b/debian/patches/fix-migration-fake-initial-1.patch +index 63513b8..915562d 100644 +--- a/debian/patches/fix-migration-fake-initial-1.patch ++++ b/debian/patches/fix-migration-fake-initial-1.patch +@@ -1,9 +1,13 @@ +-From c6d66195d7f816aeb47a77570bdd3836a99d4183 Mon Sep 17 00:00:00 2001 +-From: =?UTF-8?q?Rapha=C3=ABl=20Hertzog?= ++From: =?utf-8?q?Rapha=C3=ABl_Hertzog?= + Date: Mon, 29 May 2017 15:44:39 +0200 + Subject: [PATCH 1/2] Move detect_soft_applied() from + django.db.migrations.executor to .loader + MIME-Version: 1.0 ++Content-Type: text/plain; charset="utf-8" ++Content-Transfer-Encoding: 8bit ++ ++From c6d66195d7f816aeb47a77570bdd3836a99d4183 Mon Sep 17 00:00:00 2001 ++MIME-Version: 1.0 + Content-Type: text/plain; charset=UTF-8 + Content-Transfer-Encoding: 8bit + +@@ -17,11 +21,13 @@ Signed-off-by: Raphaƫl Hertzog + Bug: https://code.djangoproject.com/ticket/28250 + Bug-Debian: https://bugs.debian.org/863267 + --- +- django/db/migrations/executor.py | 83 +-------------------------------------- +- django/db/migrations/loader.py | 81 ++++++++++++++++++++++++++++++++++++++ ++ django/db/migrations/executor.py | 83 +------------------------------------ ++ django/db/migrations/loader.py | 86 +++++++++++++++++++++++++++++++++++++-- + tests/migrations/test_executor.py | 12 +++--- +- 3 files changed, 88 insertions(+), 88 deletions(-) ++ 3 files changed, 90 insertions(+), 91 deletions(-) + ++diff --git a/django/db/migrations/executor.py b/django/db/migrations/executor.py ++index 1a0b6f6..2ac787b 100644 + --- a/django/db/migrations/executor.py + +++ b/django/db/migrations/executor.py + @@ -1,8 +1,5 @@ +@@ -124,6 +130,8 @@ Bug-Debian: https://bugs.debian.org/863267 + - # If we get this far and we found at least one CreateModel or AddField migration, + - # the migration is considered implicitly applied. + - return (found_create_model_migration or found_add_field_migration), after_state ++diff --git a/django/db/migrations/loader.py b/django/db/migrations/loader.py ++index 3a34e6d..4904343 100644 + --- a/django/db/migrations/loader.py + +++ b/django/db/migrations/loader.py + @@ -4,8 +4,9 @@ import os +@@ -238,6 +246,8 @@ Bug-Debian: https://bugs.debian.org/863267 + + # If we get this far and we found at least one CreateModel or AddField migration, + + # the migration is considered implicitly applied. + + return (found_create_model_migration or found_add_field_migration), after_state ++diff --git a/tests/migrations/test_executor.py b/tests/migrations/test_executor.py ++index 847b11c..d0f5228 100644 + --- a/tests/migrations/test_executor.py + +++ b/tests/migrations/test_executor.py + @@ -326,7 +326,7 @@ class ExecutorTests(MigrationTestBase): +diff --git a/debian/patches/fix-migration-fake-initial-2.patch b/debian/patches/fix-migration-fake-initial-2.patch +index bb29c2f..286d211 100644 +--- a/debian/patches/fix-migration-fake-initial-2.patch ++++ b/debian/patches/fix-migration-fake-initial-2.patch +@@ -1,9 +1,13 @@ +-From e4ed4431d5730e4a8efc3d76d79ee5c16b5a2340 Mon Sep 17 00:00:00 2001 + From: Marten Kenbeek + Date: Wed, 31 May 2017 13:35:43 +0200 + Subject: [PATCH] Fixed #25850 -- Ignored soft applied migrations in + consistency check. + MIME-Version: 1.0 ++Content-Type: text/plain; charset="utf-8" ++Content-Transfer-Encoding: 8bit ++ ++From e4ed4431d5730e4a8efc3d76d79ee5c16b5a2340 Mon Sep 17 00:00:00 2001 ++MIME-Version: 1.0 + Content-Type: text/plain; charset=UTF-8 + Content-Transfer-Encoding: 8bit + +@@ -25,9 +29,11 @@ Bug-Debian: https://bugs.debian.org/863267 + django/db/migrations/executor.py | 7 ++- + django/db/migrations/loader.py | 28 +++++++--- + tests/migrations/test_executor.py | 63 +++++++++++++++++++++-- +- tests/migrations/test_loader.py | 27 ++++++++++ +- 6 files changed, 114 insertions(+), 15 deletions(-) ++ tests/migrations/test_loader.py | 27 +++++++++- ++ 6 files changed, 113 insertions(+), 16 deletions(-) + ++diff --git a/django/core/management/commands/makemigrations.py b/django/core/management/commands/makemigrations.py ++index 486c897..ec7d057 100644 + --- a/django/core/management/commands/makemigrations.py + +++ b/django/core/management/commands/makemigrations.py + @@ -106,7 +106,7 @@ class Command(BaseCommand): +@@ -39,6 +45,8 @@ Bug-Debian: https://bugs.debian.org/863267 + + # Before anything else, see if there's conflicting apps and drop out + # hard if there are any and they don't want to merge ++diff --git a/django/core/management/commands/migrate.py b/django/core/management/commands/migrate.py ++index 6846b33..784a70b 100644 + --- a/django/core/management/commands/migrate.py + +++ b/django/core/management/commands/migrate.py + @@ -83,7 +83,7 @@ class Command(BaseCommand): +@@ -50,6 +58,8 @@ Bug-Debian: https://bugs.debian.org/863267 + + # Before anything else, see if there's conflicting apps and drop out + # hard if there are any ++diff --git a/django/db/migrations/executor.py b/django/db/migrations/executor.py ++index 2ac787b..f8d46cf 100644 + --- a/django/db/migrations/executor.py + +++ b/django/db/migrations/executor.py + @@ -76,6 +76,11 @@ class MigrationExecutor(object): +@@ -73,6 +83,8 @@ Bug-Debian: https://bugs.debian.org/863267 + if applied: + fake = True + if not fake: ++diff --git a/django/db/migrations/loader.py b/django/db/migrations/loader.py ++index 4904343..95b2c3d 100644 + --- a/django/db/migrations/loader.py + +++ b/django/db/migrations/loader.py + @@ -268,13 +268,14 @@ class MigrationLoader(object): +@@ -152,6 +164,8 @@ Bug-Debian: https://bugs.debian.org/863267 + ] + if field.column not in column_names: + return False, project_state ++diff --git a/tests/migrations/test_executor.py b/tests/migrations/test_executor.py ++index d0f5228..8c26198 100644 + --- a/tests/migrations/test_executor.py + +++ b/tests/migrations/test_executor.py + @@ -297,6 +297,59 @@ class ExecutorTests(MigrationTestBase): +@@ -253,9 +267,11 @@ Bug-Debian: https://bugs.debian.org/863267 + + # Cleanup by removing the remaining tables. + with connection.schema_editor() as editor: ++diff --git a/tests/migrations/test_loader.py b/tests/migrations/test_loader.py ++index c269837..df12b37 100644 + --- a/tests/migrations/test_loader.py + +++ b/tests/migrations/test_loader.py +-@@ -8,7 +8,7 @@ from django.db.migrations.exceptions imp ++@@ -8,7 +8,7 @@ from django.db.migrations.exceptions import ( + ) + from django.db.migrations.loader import MigrationLoader + from django.db.migrations.recorder import MigrationRecorder +@@ -264,10 +280,11 @@ Bug-Debian: https://bugs.debian.org/863267 + from django.utils import six + + +-@@ -402,6 +402,31 @@ class LoaderTests(TestCase): ++@@ -401,6 +401,31 @@ class LoaderTests(TestCase): ++ recorder.record_applied('migrations', '0003_third') + loader.check_consistent_history(connection) + +- @override_settings(MIGRATION_MODULES={ +++ @override_settings(MIGRATION_MODULES={ + + "migrations": "migrations.test_migrations_first", + + "migrations2": "migrations2.test_migrations_2_first", + + }) +@@ -292,7 +309,6 @@ Bug-Debian: https://bugs.debian.org/863267 + + with self.assertRaisesMessage(InconsistentMigrationHistory, msg): + + loader.check_consistent_history(connection, fake_initial=True) + + +-+ @override_settings(MIGRATION_MODULES={ ++ @override_settings(MIGRATION_MODULES={ + "app1": "migrations.test_migrations_squashed_ref_squashed.app1", + "app2": "migrations.test_migrations_squashed_ref_squashed.app2", +- }) +diff --git a/debian/patches/fix-test-middleware-classes-headers.patch b/debian/patches/fix-test-middleware-classes-headers.patch +index 3d7e0a3..4b2e75f 100644 +--- a/debian/patches/fix-test-middleware-classes-headers.patch ++++ b/debian/patches/fix-test-middleware-classes-headers.patch +@@ -1,4 +1,3 @@ +-From fa63fc91ccc08b20ed4ca45e73f7aad2b38d9171 Mon Sep 17 00:00:00 2001 + From: Chris Lamb + Date: Wed, 31 May 2017 15:25:09 +0100 + Subject: [PATCH] [1.11.x] Fixed #26755 -- Fixed +@@ -13,7 +12,7 @@ Bug-Debian: https://bugs.debian.org/816435 + 1 file changed, 10 insertions(+), 8 deletions(-) + + diff --git a/tests/project_template/test_settings.py b/tests/project_template/test_settings.py +-index a0047dd836d..791c42e03ae 100644 ++index d153c4d..c24a08e 100644 + --- a/tests/project_template/test_settings.py + +++ b/tests/project_template/test_settings.py + @@ -1,11 +1,12 @@ +@@ -30,7 +29,7 @@ index a0047dd836d..791c42e03ae 100644 + + + @unittest.skipIf( +-@@ -15,16 +16,16 @@ ++@@ -15,16 +16,16 @@ from django.utils._os import upath + ) + class TestStartProjectSettings(TestCase): + def setUp(self): +@@ -53,7 +52,7 @@ index a0047dd836d..791c42e03ae 100644 + + def test_middleware_headers(self): + """ +-@@ -32,7 +33,8 @@ def test_middleware_headers(self): ++@@ -32,7 +33,8 @@ class TestStartProjectSettings(TestCase): + change. For example, we never want "Vary: Cookie" to appear in the list + since it prevents the caching of responses. + """ +diff --git a/debian/patches/series b/debian/patches/series +index 6ccbb74..f588a67 100644 +--- a/debian/patches/series ++++ b/debian/patches/series +@@ -8,3 +8,4 @@ fix-test-middleware-classes-headers.patch + 0015-CVE-2018-14574.patch + 0016-CVE-2017-12794.patch + 0006-Default-to-supporting-Spatialite-4.2.patch ++0011-Fixed-30070-CVE-2019-3498-Fixed-content-spoofing-pos.patch +diff --git a/django/views/defaults.py b/django/views/defaults.py +index 348837e..5ec9ac8 100644 +--- a/django/views/defaults.py ++++ b/django/views/defaults.py +@@ -2,6 +2,7 @@ from django import http + from django.template import Context, Engine, TemplateDoesNotExist, loader + from django.utils import six + from django.utils.encoding import force_text ++from django.utils.http import urlquote + from django.views.decorators.csrf import requires_csrf_token + + ERROR_404_TEMPLATE_NAME = '404.html' +@@ -21,7 +22,8 @@ def page_not_found(request, exception, template_name=ERROR_404_TEMPLATE_NAME): + Templates: :template:`404.html` + Context: + request_path +- The path of the requested URL (e.g., '/app/pages/bad_page/') ++ The path of the requested URL (e.g., '/app/pages/bad_page/'). It's ++ quoted to prevent a content injection attack. + exception + The message from the exception which triggered the 404 (if one was + supplied), or the exception class name +@@ -37,7 +39,7 @@ def page_not_found(request, exception, template_name=ERROR_404_TEMPLATE_NAME): + if isinstance(message, six.text_type): + exception_repr = message + context = { +- 'request_path': request.path, ++ 'request_path': urlquote(request.path), + 'exception': exception_repr, + } + try: +@@ -50,7 +52,7 @@ def page_not_found(request, exception, template_name=ERROR_404_TEMPLATE_NAME): + raise + template = Engine().from_string( + '

Not Found

' +- '

The requested URL {{ request_path }} was not found on this server.

') ++ '

The requested resource was not found on this server.

') + body = template.render(Context(context)) + content_type = 'text/html' + return http.HttpResponseNotFound(body, content_type=content_type) +diff --git a/tests/handlers/tests.py b/tests/handlers/tests.py +index 9f01cb2..50a3488 100644 +--- a/tests/handlers/tests.py ++++ b/tests/handlers/tests.py +@@ -2,6 +2,7 @@ + + from __future__ import unicode_literals + ++import sys + import unittest + + from django.core.exceptions import ImproperlyConfigured +@@ -19,6 +20,8 @@ try: + except ImportError: # Python < 3.5 + HTTPStatus = None + ++PY37 = sys.version_info >= (3, 7, 0) ++ + + class HandlerTests(SimpleTestCase): + +@@ -180,16 +183,17 @@ class HandlerRequestTests(SimpleTestCase): + + def test_invalid_urls(self): + response = self.client.get('~%A9helloworld') +- self.assertContains(response, '~%A9helloworld', status_code=404) ++ self.assertEqual(response.status_code, 404) ++ self.assertEqual(response.context['request_path'], '/~%25A9helloworld' if PY37 else '/%7E%25A9helloworld') + + response = self.client.get('d%aao%aaw%aan%aal%aao%aaa%aad%aa/') +- self.assertContains(response, 'd%AAo%AAw%AAn%AAl%AAo%AAa%AAd%AA', status_code=404) ++ self.assertEqual(response.context['request_path'], '/d%25AAo%25AAw%25AAn%25AAl%25AAo%25AAa%25AAd%25AA') + + response = self.client.get('/%E2%99%E2%99%A5/') +- self.assertContains(response, '%E2%99\u2665', status_code=404) ++ self.assertEqual(response.context['request_path'], '/%25E2%2599%E2%99%A5/') + + response = self.client.get('/%E2%98%8E%E2%A9%E2%99%A5/') +- self.assertContains(response, '\u260e%E2%A9\u2665', status_code=404) ++ self.assertEqual(response.context['request_path'], '/%E2%98%8E%25E2%25A9%E2%99%A5/') + + def test_environ_path_info_type(self): + environ = RequestFactory().get('/%E2%A8%87%87%A5%E2%A8%A0').environ diff --git a/debian/patches/series b/debian/patches/series index 6ccbb746a..5bda383eb 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -8,3 +8,4 @@ fix-test-middleware-classes-headers.patch 0015-CVE-2018-14574.patch 0016-CVE-2017-12794.patch 0006-Default-to-supporting-Spatialite-4.2.patch +0017-CVE-2019-3498.patch