From 2b099caa5923afa8cfb5f1e8c0d56b6e0e81915b Mon Sep 17 00:00:00 2001 From: Mariusz Felisiak Date: Fri, 21 Aug 2020 12:43:45 +0200 Subject: [PATCH] [3.1.x] Fixed CVE-2020-24584 -- Fixed permission escalation in intermediate-level directories of the file system cache on Python 3.7+. Backport of f56b57976133129b0b351a38bba4ac882badabf0 from master. --- django/core/cache/backends/filebased.py | 8 +++++++- docs/releases/2.2.16.txt | 9 ++++++++- docs/releases/3.0.10.txt | 9 ++++++++- docs/releases/3.1.1.txt | 9 ++++++++- tests/cache/tests.py | 25 ++++++++++++++++++++++++- 5 files changed, 55 insertions(+), 5 deletions(-) diff --git a/django/core/cache/backends/filebased.py b/django/core/cache/backends/filebased.py index 3d76f0371b..10779c5545 100644 --- a/django/core/cache/backends/filebased.py +++ b/django/core/cache/backends/filebased.py @@ -114,7 +114,13 @@ class FileBasedCache(BaseCache): self._delete(fname) def _createdir(self): - os.makedirs(self._dir, 0o700, exist_ok=True) + # Set the umask because os.makedirs() doesn't apply the "mode" argument + # to intermediate-level directories. + old_umask = os.umask(0o077) + try: + os.makedirs(self._dir, 0o700, exist_ok=True) + finally: + os.umask(old_umask) def _key_to_file(self, key, version=None): """ diff --git a/docs/releases/2.2.16.txt b/docs/releases/2.2.16.txt index f0c3ec894a..f531871d1a 100644 --- a/docs/releases/2.2.16.txt +++ b/docs/releases/2.2.16.txt @@ -4,7 +4,7 @@ Django 2.2.16 release notes *Expected September 1, 2020* -Django 2.2.16 fixes a security issue and two data loss bugs in 2.2.15. +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+ ====================================================================================== @@ -17,6 +17,13 @@ files and to intermediate-level collected static directories when using the You should review and manually fix permissions on existing intermediate-level directories. +CVE-2020-24584: Permission escalation in intermediate-level directories of the file system cache on Python 3.7+ +=============================================================================================================== + +On Python 3.7+, the intermediate-level directories of the file system cache had +the system's standard umask rather than ``0o077`` (no group or others +permissions). + Bugfixes ======== diff --git a/docs/releases/3.0.10.txt b/docs/releases/3.0.10.txt index 4238a9fd71..ebc67d4725 100644 --- a/docs/releases/3.0.10.txt +++ b/docs/releases/3.0.10.txt @@ -4,7 +4,7 @@ Django 3.0.10 release notes *Expected September 1, 2020* -Django 3.0.10 fixes a security issue and two data loss bugs in 3.0.9. +Django 3.0.10 fixes two security issues and two data loss bugs in 3.0.9. CVE-2020-24583: Incorrect permissions on intermediate-level directories on Python 3.7+ ====================================================================================== @@ -17,6 +17,13 @@ files and to intermediate-level collected static directories when using the You should review and manually fix permissions on existing intermediate-level directories. +CVE-2020-24584: Permission escalation in intermediate-level directories of the file system cache on Python 3.7+ +=============================================================================================================== + +On Python 3.7+, the intermediate-level directories of the file system cache had +the system's standard umask rather than ``0o077`` (no group or others +permissions). + Bugfixes ======== diff --git a/docs/releases/3.1.1.txt b/docs/releases/3.1.1.txt index 11a935dda7..ad5d3ae512 100644 --- a/docs/releases/3.1.1.txt +++ b/docs/releases/3.1.1.txt @@ -4,7 +4,7 @@ Django 3.1.1 release notes *Expected September 1, 2020* -Django 3.1.1 fixes a security issue and several bugs in 3.1. +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+ ====================================================================================== @@ -17,6 +17,13 @@ files and to intermediate-level collected static directories when using the You should review and manually fix permissions on existing intermediate-level directories. +CVE-2020-24584: Permission escalation in intermediate-level directories of the file system cache on Python 3.7+ +=============================================================================================================== + +On Python 3.7+, the intermediate-level directories of the file system cache had +the system's standard umask rather than ``0o077`` (no group or others +permissions). + Bugfixes ======== diff --git a/tests/cache/tests.py b/tests/cache/tests.py index b85b5e8501..cc0c86cd4a 100644 --- a/tests/cache/tests.py +++ b/tests/cache/tests.py @@ -6,12 +6,13 @@ import os import pickle import re import shutil +import sys import tempfile import threading import time import unittest from pathlib import Path -from unittest import mock +from unittest import mock, skipIf from django.conf import settings from django.core import management, signals @@ -1466,6 +1467,28 @@ class FileBasedCacheTests(BaseCacheTests, TestCase): # Returns the default instead of erroring. self.assertEqual(cache.get('foo', 'baz'), 'baz') + @skipIf( + sys.platform == 'win32', + 'Windows only partially supports umasks and chmod.', + ) + def test_cache_dir_permissions(self): + os.rmdir(self.dirname) + dir_path = Path(self.dirname) / 'nested' / 'filebasedcache' + for cache_params in settings.CACHES.values(): + cache_params['LOCATION'] = dir_path + setting_changed.send(self.__class__, setting='CACHES', enter=False) + cache.set('foo', 'bar') + self.assertIs(dir_path.exists(), True) + tests = [ + dir_path, + dir_path.parent, + dir_path.parent.parent, + ] + for directory in tests: + with self.subTest(directory=directory): + dir_mode = directory.stat().st_mode & 0o777 + self.assertEqual(dir_mode, 0o700) + def test_get_does_not_ignore_non_filenotfound_exceptions(self): with mock.patch('builtins.open', side_effect=OSError): with self.assertRaises(OSError):