Reference: https://nvd.nist.gov/vuln/detail/CVE-2024-39329
Upstream-patch: https://github.com/django/django/commit/156d3186c96e3ec2ca73b8b25dc2ef366e38df14 Signed-off-by: Saravanan <[email protected]> --- .../CVE-2024-39329.patch | 114 ++++++++++++++++++ .../python3-django/CVE-2024-39329.patch | 111 +++++++++++++++++ .../python/python3-django_2.2.28.bb | 1 + .../python/python3-django_3.2.25.bb | 1 + 4 files changed, 227 insertions(+) create mode 100644 meta-python/recipes-devtools/python/python3-django-3.2.25/CVE-2024-39329.patch create mode 100644 meta-python/recipes-devtools/python/python3-django/CVE-2024-39329.patch diff --git a/meta-python/recipes-devtools/python/python3-django-3.2.25/CVE-2024-39329.patch b/meta-python/recipes-devtools/python/python3-django-3.2.25/CVE-2024-39329.patch new file mode 100644 index 0000000000..9f2883885f --- /dev/null +++ b/meta-python/recipes-devtools/python/python3-django-3.2.25/CVE-2024-39329.patch @@ -0,0 +1,114 @@ +From 156d3186c96e3ec2ca73b8b25dc2ef366e38df14 Mon Sep 17 00:00:00 2001 +From: Michael Manfre <[email protected]> +Date: Fri, 14 Jun 2024 22:12:58 -0400 +Subject: [PATCH] Fixed CVE-2024-39329 -- Standarized timing of + verify_password() when checking unusuable passwords. + +Refs #20760. + +Thanks Michael Manfre for the fix and to Adam Johnson for the review. + +CVE: CVE-2024-39329 + +Upstream-Status: Backport +https://github.com/django/django/commit/156d3186c96e3ec2ca73b8b25dc2ef366e38df14 + +Signed-off-by: Michael Manfre <[email protected]> +Signed-off-by: Saravanan <[email protected]> +--- + django/contrib/auth/hashers.py | 10 ++++++++-- + docs/releases/3.2.25.txt | 7 +++++++ + tests/auth_tests/test_hashers.py | 32 ++++++++++++++++++++++++++++++++ + 3 files changed, 47 insertions(+), 2 deletions(-) + +diff --git a/django/contrib/auth/hashers.py b/django/contrib/auth/hashers.py +index 86ae7f4..ee81b64 100644 +--- a/django/contrib/auth/hashers.py ++++ b/django/contrib/auth/hashers.py +@@ -36,14 +36,20 @@ def check_password(password, encoded, setter=None, preferred='default'): + If setter is specified, it'll be called when you need to + regenerate the password. + """ +- if password is None or not is_password_usable(encoded): +- return False ++ fake_runtime = password is None or not is_password_usable(encoded) + + preferred = get_hasher(preferred) + try: + hasher = identify_hasher(encoded) + except ValueError: + # encoded is gibberish or uses a hasher that's no longer installed. ++ fake_runtime = True ++ ++ if fake_runtime: ++ # Run the default password hasher once to reduce the timing difference ++ # between an existing user with an unusable password and a nonexistent ++ # user or missing hasher (similar to #20760). ++ make_password(get_random_string(UNUSABLE_PASSWORD_SUFFIX_LENGTH)) + return False + + hasher_changed = hasher.algorithm != preferred.algorithm +diff --git a/docs/releases/3.2.25.txt b/docs/releases/3.2.25.txt +index a2a58b5..a613b08 100644 +--- a/docs/releases/3.2.25.txt ++++ b/docs/releases/3.2.25.txt +@@ -40,6 +40,13 @@ CVE-2025-57833: Potential SQL injection in ``FilteredRelation`` column aliases + using a suitably crafted dictionary, with dictionary expansion, as the + ``**kwargs`` passed to :meth:`.QuerySet.annotate` or :meth:`.QuerySet.alias`. + ++CVE-2024-39329: Username enumeration through timing difference for users with unusable passwords ++================================================================================================ ++ ++The :meth:`~django.contrib.auth.backends.ModelBackend.authenticate()` method ++allowed remote attackers to enumerate users via a timing attack involving login ++requests for users with unusable passwords. ++ + Bugfixes + ======== + +diff --git a/tests/auth_tests/test_hashers.py b/tests/auth_tests/test_hashers.py +index 8bc61bc..a1ae940 100644 +--- a/tests/auth_tests/test_hashers.py ++++ b/tests/auth_tests/test_hashers.py +@@ -474,6 +474,38 @@ class TestUtilsHashPass(SimpleTestCase): + check_password('wrong_password', encoded) + self.assertEqual(hasher.harden_runtime.call_count, 1) + ++ def test_check_password_calls_make_password_to_fake_runtime(self): ++ hasher = get_hasher("default") ++ cases = [ ++ (None, None, None), # no plain text password provided ++ ("foo", make_password(password=None), None), # unusable encoded ++ ("letmein", make_password(password="letmein"), ValueError), # valid encoded ++ ] ++ for password, encoded, hasher_side_effect in cases: ++ with ( ++ self.subTest(encoded=encoded), ++ mock.patch( ++ "django.contrib.auth.hashers.identify_hasher", ++ side_effect=hasher_side_effect, ++ ) as mock_identify_hasher, ++ mock.patch( ++ "django.contrib.auth.hashers.make_password" ++ ) as mock_make_password, ++ mock.patch( ++ "django.contrib.auth.hashers.get_random_string", ++ side_effect=lambda size: "x" * size, ++ ), ++ mock.patch.object(hasher, "verify"), ++ ): ++ # Ensure make_password is called to standardize timing. ++ check_password(password, encoded) ++ self.assertEqual(hasher.verify.call_count, 0) ++ self.assertEqual(mock_identify_hasher.mock_calls, [mock.call(encoded)]) ++ self.assertEqual( ++ mock_make_password.mock_calls, ++ [mock.call("x" * UNUSABLE_PASSWORD_SUFFIX_LENGTH)], ++ ) ++ + + class BasePasswordHasherTests(SimpleTestCase): + not_implemented_msg = 'subclasses of BasePasswordHasher must provide %s() method' +-- +2.40.0 + diff --git a/meta-python/recipes-devtools/python/python3-django/CVE-2024-39329.patch b/meta-python/recipes-devtools/python/python3-django/CVE-2024-39329.patch new file mode 100644 index 0000000000..c302c0df18 --- /dev/null +++ b/meta-python/recipes-devtools/python/python3-django/CVE-2024-39329.patch @@ -0,0 +1,111 @@ +From 156d3186c96e3ec2ca73b8b25dc2ef366e38df14 Mon Sep 17 00:00:00 2001 +From: Michael Manfre <[email protected]> +Date: Fri, 14 Jun 2024 22:12:58 -0400 +Subject: [PATCH] Fixed CVE-2024-39329 -- Standarized timing of + verify_password() when checking unusuable passwords. + +Refs #20760. + +Thanks Michael Manfre for the fix and to Adam Johnson for the review. + +CVE: CVE-2024-39329 + +Upstream-Status: Backport +https://github.com/django/django/commit/156d3186c96e3ec2ca73b8b25dc2ef366e38df14 + +Signed-off-by: Michael Manfre <[email protected]> +Signed-off-by: Saravanan <[email protected]> +--- + django/contrib/auth/hashers.py | 10 ++++++++-- + docs/releases/2.2.28.txt | 7 +++++++ + tests/auth_tests/test_hashers.py | 32 ++++++++++++++++++++++++++++++++ + 3 files changed, 47 insertions(+), 2 deletions(-) + +diff --git a/django/contrib/auth/hashers.py b/django/contrib/auth/hashers.py +index 1e8d754..4acb81d 100644 +--- a/django/contrib/auth/hashers.py ++++ b/django/contrib/auth/hashers.py +@@ -36,14 +36,20 @@ def check_password(password, encoded, setter=None, preferred='default'): + If setter is specified, it'll be called when you need to + regenerate the password. + """ +- if password is None or not is_password_usable(encoded): +- return False ++ fake_runtime = password is None or not is_password_usable(encoded) + + preferred = get_hasher(preferred) + try: + hasher = identify_hasher(encoded) + except ValueError: + # encoded is gibberish or uses a hasher that's no longer installed. ++ fake_runtime = True ++ ++ if fake_runtime: ++ # Run the default password hasher once to reduce the timing difference ++ # between an existing user with an unusable password and a nonexistent ++ # user or missing hasher (similar to #20760). ++ make_password(get_random_string(UNUSABLE_PASSWORD_SUFFIX_LENGTH)) + return False + + hasher_changed = hasher.algorithm != preferred.algorithm +diff --git a/docs/releases/2.2.28.txt b/docs/releases/2.2.28.txt +index f3fb298..22fa80e 100644 +--- a/docs/releases/2.2.28.txt ++++ b/docs/releases/2.2.28.txt +@@ -124,3 +124,10 @@ CVE-2025-57833: Potential SQL injection in ``FilteredRelation`` column aliases + using a suitably crafted dictionary, with dictionary expansion, as the + ``**kwargs`` passed to :meth:`.QuerySet.annotate` or :meth:`.QuerySet.alias`. + ++CVE-2024-39329: Username enumeration through timing difference for users with unusable passwords ++================================================================================================ ++ ++The :meth:`~django.contrib.auth.backends.ModelBackend.authenticate()` method ++allowed remote attackers to enumerate users via a timing attack involving login ++requests for users with unusable passwords. ++ +diff --git a/tests/auth_tests/test_hashers.py b/tests/auth_tests/test_hashers.py +index ee6441b..391b3cc 100644 +--- a/tests/auth_tests/test_hashers.py ++++ b/tests/auth_tests/test_hashers.py +@@ -433,6 +433,38 @@ class TestUtilsHashPass(SimpleTestCase): + check_password('wrong_password', encoded) + self.assertEqual(hasher.harden_runtime.call_count, 1) + ++ def test_check_password_calls_make_password_to_fake_runtime(self): ++ hasher = get_hasher("default") ++ cases = [ ++ (None, None, None), # no plain text password provided ++ ("foo", make_password(password=None), None), # unusable encoded ++ ("letmein", make_password(password="letmein"), ValueError), # valid encoded ++ ] ++ for password, encoded, hasher_side_effect in cases: ++ with ( ++ self.subTest(encoded=encoded), ++ mock.patch( ++ "django.contrib.auth.hashers.identify_hasher", ++ side_effect=hasher_side_effect, ++ ) as mock_identify_hasher, ++ mock.patch( ++ "django.contrib.auth.hashers.make_password" ++ ) as mock_make_password, ++ mock.patch( ++ "django.contrib.auth.hashers.get_random_string", ++ side_effect=lambda size: "x" * size, ++ ), ++ mock.patch.object(hasher, "verify"), ++ ): ++ # Ensure make_password is called to standardize timing. ++ check_password(password, encoded) ++ self.assertEqual(hasher.verify.call_count, 0) ++ self.assertEqual(mock_identify_hasher.mock_calls, [mock.call(encoded)]) ++ self.assertEqual( ++ mock_make_password.mock_calls, ++ [mock.call("x" * UNUSABLE_PASSWORD_SUFFIX_LENGTH)], ++ ) ++ + + class BasePasswordHasherTests(SimpleTestCase): + not_implemented_msg = 'subclasses of BasePasswordHasher must provide %s() method' +-- +2.40.0 + diff --git a/meta-python/recipes-devtools/python/python3-django_2.2.28.bb b/meta-python/recipes-devtools/python/python3-django_2.2.28.bb index 82cdcb2328..3000e93f81 100644 --- a/meta-python/recipes-devtools/python/python3-django_2.2.28.bb +++ b/meta-python/recipes-devtools/python/python3-django_2.2.28.bb @@ -28,6 +28,7 @@ SRC_URI += "file://CVE-2023-31047.patch \ file://CVE-2025-26699.patch \ file://CVE-2024-56374.patch \ file://CVE-2025-57833.patch \ + file://CVE-2024-39329.patch \ " SRC_URI[sha256sum] = "0200b657afbf1bc08003845ddda053c7641b9b24951e52acd51f6abda33a7413" diff --git a/meta-python/recipes-devtools/python/python3-django_3.2.25.bb b/meta-python/recipes-devtools/python/python3-django_3.2.25.bb index fe438016f9..4301eccaae 100644 --- a/meta-python/recipes-devtools/python/python3-django_3.2.25.bb +++ b/meta-python/recipes-devtools/python/python3-django_3.2.25.bb @@ -10,6 +10,7 @@ SRC_URI += "\ file://CVE-2025-26699.patch \ file://CVE-2024-56374.patch \ file://CVE-2025-57833.patch \ + file://CVE-2024-39329.patch \ " # Set DEFAULT_PREFERENCE so that the LTS version of django is built by -- 2.35.5
-=-=-=-=-=-=-=-=-=-=-=- Links: You receive all messages sent to this group. View/Reply Online (#122168): https://lists.openembedded.org/g/openembedded-devel/message/122168 Mute This Topic: https://lists.openembedded.org/mt/116537752/21656 Group Owner: [email protected] Unsubscribe: https://lists.openembedded.org/g/openembedded-devel/unsub [[email protected]] -=-=-=-=-=-=-=-=-=-=-=-
