From eb6899410d9794ebc4b1cfec7e596b24dc1a4891 Mon Sep 17 00:00:00 2001 From: OpenShift Cherrypick Robot Date: Tue, 27 May 2025 21:07:08 +0200 Subject: [PATCH] [redhat-3.10] proxycache(permissions): CVE-2025-4374 (PROJQUAY-8892) (#3963) fixing CVE-2025-4374 by extending the create_repository method to understand if we are requesting a proxy_cache repository added unittests for create_repository when proxy_cache. Co-authored-by: Michaela Lang --- data/model/repository.py | 11 ++++++-- data/model/test/test_repository.py | 29 +++++++++++++++++++++ data/registry_model/registry_proxy_model.py | 4 ++- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/data/model/repository.py b/data/model/repository.py index 2e3e2118d..fd050304a 100644 --- a/data/model/repository.py +++ b/data/model/repository.py @@ -126,7 +126,13 @@ class _RepositoryExistsException(Exception): def create_repository( - namespace, name, creating_user, visibility="private", repo_kind="image", description=None + namespace, + name, + creating_user, + visibility="private", + repo_kind="image", + description=None, + proxy_cache=False, ): namespace_user = User.get(username=namespace) yesterday = datetime.now() - timedelta(days=1) @@ -154,7 +160,8 @@ def create_repository( # Note: We put the admin create permission under the transaction to ensure it is created. if creating_user and not creating_user.organization: - admin = Role.get(name="admin") + rolename = "admin" if proxy_cache == False else "read" + admin = Role.get(name=rolename) RepositoryPermission.create(user=creating_user, repository=repo, role=admin) except _RepositoryExistsException as ree: try: diff --git a/data/model/test/test_repository.py b/data/model/test/test_repository.py index 96a681c17..2ad1ec857 100644 --- a/data/model/test/test_repository.py +++ b/data/model/test/test_repository.py @@ -3,6 +3,11 @@ from datetime import timedelta import pytest +from auth.permissions import ( + AdministerRepositoryPermission, + ModifyRepositoryPermission, + ReadRepositoryPermission, +) from data.database import BlobUpload, QuotaRepositorySize, Repository from data.model.repository import ( create_repository, @@ -105,3 +110,27 @@ def test_get_repository_sizes(initialized_db): repo2.id: 92, repo3.id: 0, } + + +@pytest.fixture() +def test_create_repository_proxy_cache(initialized_db): + # with CVE-2025-4374 we want to ensure that repositories in PROXY_CACHE are not assigned to "admin" + repo1 = create_repository( + "devtable", + "somenewrepo", + None, + repo_kind="image", + visibility="public", + proxy_cache=True, + ) + # we should not have modify or admin permissions on the repo if created with proxy_cache=True + if all( + [ + ReadRepositoryPermission("devtable", "somenewrepo").can(), + not ModifyRepositoryPermission("devtable", "somenewrepo").can(), + not AdministerRepositoryPermission("devtable", "somenewrepo").can(), + ] + ): + assert True + else: + assert False diff --git a/data/registry_model/registry_proxy_model.py b/data/registry_model/registry_proxy_model.py index 0a0e00557..160904e64 100644 --- a/data/registry_model/registry_proxy_model.py +++ b/data/registry_model/registry_proxy_model.py @@ -127,7 +127,9 @@ class ProxyModel(OCIModel): visibility = "private" if app.config.get("CREATE_PRIVATE_REPO_ON_PUSH", True) else "public" - repo = create_repository(namespace_name, repo_name, self._user, visibility=visibility) + repo = create_repository( + namespace_name, repo_name, self._user, visibility=visibility, proxy_cache=True + ) return RepositoryReference.for_repo_obj( repo, namespace_name,