diff --git a/vulnerabilities/importers/__init__.py b/vulnerabilities/importers/__init__.py index 8aa9961d5..9ca4d7cd5 100644 --- a/vulnerabilities/importers/__init__.py +++ b/vulnerabilities/importers/__init__.py @@ -50,6 +50,7 @@ ) from vulnerabilities.pipelines.v2_importers import epss_importer_v2 from vulnerabilities.pipelines.v2_importers import fireeye_importer_v2 +from vulnerabilities.pipelines.v2_importers import gentoo_importer as gentoo_importer_v2 from vulnerabilities.pipelines.v2_importers import github_osv_importer as github_osv_importer_v2 from vulnerabilities.pipelines.v2_importers import gitlab_importer as gitlab_importer_v2 from vulnerabilities.pipelines.v2_importers import istio_importer as istio_importer_v2 @@ -89,6 +90,7 @@ aosp_importer_v2.AospImporterPipeline, ruby_importer_v2.RubyImporterPipeline, epss_importer_v2.EPSSImporterPipeline, + gentoo_importer_v2.GentooImporterPipeline, mattermost_importer_v2.MattermostImporterPipeline, nvd_importer.NVDImporterPipeline, github_importer.GitHubAPIImporterPipeline, diff --git a/vulnerabilities/importers/gentoo.py b/vulnerabilities/importers/gentoo.py index 2f569cdf1..0f3be4431 100644 --- a/vulnerabilities/importers/gentoo.py +++ b/vulnerabilities/importers/gentoo.py @@ -6,8 +6,7 @@ # See https://github.com/aboutcode-org/vulnerablecode for support or download. # See https://aboutcode.org for more information about nexB OSS projects. # - - +import logging import re import xml.etree.ElementTree as ET from pathlib import Path @@ -17,12 +16,15 @@ from univers.version_constraint import VersionConstraint from univers.version_range import EbuildVersionRange from univers.versions import GentooVersion +from univers.versions import InvalidVersion from vulnerabilities.importer import AdvisoryData from vulnerabilities.importer import AffectedPackage from vulnerabilities.importer import Importer from vulnerabilities.importer import Reference +logger = logging.getLogger(__name__) + class GentooImporter(Importer): repo_url = "git+https://anongit.gentoo.org/git/data/glsa.git" @@ -104,14 +106,20 @@ def affected_and_safe_purls(affected_elem): safe_versions, affected_versions = GentooImporter.get_safe_and_affected_versions(pkg) for version in safe_versions: - constraints.append( - VersionConstraint(version=GentooVersion(version), comparator="=").invert() - ) + try: + constraints.append( + VersionConstraint(version=GentooVersion(version), comparator="=").invert() + ) + except InvalidVersion as e: + logger.error(f"Invalid safe_version {version} - error: {e}") for version in affected_versions: - constraints.append( - VersionConstraint(version=GentooVersion(version), comparator="=") - ) + try: + constraints.append( + VersionConstraint(version=GentooVersion(version), comparator="=") + ) + except InvalidVersion as e: + logger.error(f"Invalid affected_version {version} - error: {e}") if not constraints: continue diff --git a/vulnerabilities/pipelines/v2_importers/gentoo_importer.py b/vulnerabilities/pipelines/v2_importers/gentoo_importer.py new file mode 100644 index 000000000..7101ed8f2 --- /dev/null +++ b/vulnerabilities/pipelines/v2_importers/gentoo_importer.py @@ -0,0 +1,193 @@ +# +# Copyright (c) nexB Inc. and others. All rights reserved. +# VulnerableCode is a trademark of nexB Inc. +# SPDX-License-Identifier: Apache-2.0 +# See http://www.apache.org/licenses/LICENSE-2.0 for the license text. +# See https://github.com/aboutcode-org/vulnerablecode for support or download. +# See https://aboutcode.org for more information about nexB OSS projects. +# + +import re +import xml.etree.ElementTree as ET +from pathlib import Path +from typing import Iterable + +from fetchcode.vcs import fetch_via_vcs +from packageurl import PackageURL +from univers.version_constraint import VersionConstraint +from univers.version_range import EbuildVersionRange +from univers.versions import GentooVersion +from univers.versions import InvalidVersion + +from vulnerabilities.importer import AdvisoryData +from vulnerabilities.importer import AffectedPackageV2 +from vulnerabilities.importer import ReferenceV2 +from vulnerabilities.importer import VulnerabilitySeverity +from vulnerabilities.management.commands.commit_export import logger +from vulnerabilities.pipelines import VulnerableCodeBaseImporterPipelineV2 +from vulnerabilities.severity_systems import GENERIC + + +class GentooImporterPipeline(VulnerableCodeBaseImporterPipelineV2): + repo_url = "git+https://anongit.gentoo.org/git/data/glsa.git" + spdx_license_expression = "CC-BY-SA-4.0" + # the license notice is at this url https://anongit.gentoo.org/ says: + # The contents of this document, unless otherwise expressly stated, are licensed + # under the [CC-BY-SA-4.0](https://creativecommons.org/licenses/by-sa/4.0/) license. + license_url = "https://creativecommons.org/licenses/by-sa/4.0/" + pipeline_id = "gentoo_importer_v2" + + @classmethod + def steps(cls): + return ( + cls.clone, + cls.collect_and_store_advisories, + cls.clean_downloads, + ) + + def clone(self): + self.log(f"Cloning `{self.repo_url}`") + self.vcs_response = fetch_via_vcs(self.repo_url) + + def advisories_count(self): + advisory_dir = Path(self.vcs_response.dest_dir) + return sum(1 for _ in advisory_dir.rglob("*.xml")) + + def collect_advisories(self) -> Iterable[AdvisoryData]: + base_path = Path(self.vcs_response.dest_dir) + for file_path in base_path.glob("**/*.xml"): + yield from self.process_file(file_path) + + def process_file(self, file): + cves = [] + summary = "" + xml_root = ET.parse(file).getroot() + id = xml_root.attrib.get("id") + glsa = "GLSA-" + id + vuln_references = [ + ReferenceV2( + reference_id=glsa, + url=f"https://security.gentoo.org/glsa/{id}", + ) + ] + + severities = [] + affected_packages = [] + for child in xml_root: + if child.tag == "references": + cves = self.cves_from_reference(child) + + if child.tag == "synopsis": + summary = child.text + + if child.tag == "affected": + affected_packages = [] + seen_packages = set() + + for purl, constraint in get_affected_and_safe_purls(child): + signature = (purl.to_string(), str(constraint)) + + if signature not in seen_packages: + seen_packages.add(signature) + + affected_package = AffectedPackageV2( + package=purl, + affected_version_range=EbuildVersionRange(constraints=[constraint]), + fixed_version_range=None, + ) + affected_packages.append(affected_package) + + if child.tag == "impact": + severity_value = child.attrib.get("type") + if severity_value: + severities.append(VulnerabilitySeverity(system=GENERIC, value=severity_value)) + + yield AdvisoryData( + advisory_id=glsa, + aliases=cves, + summary=summary, + references_v2=vuln_references, + severities=severities, + affected_packages=affected_packages, + url=f"https://security.gentoo.org/glsa/{id}" + if id + else "https://security.gentoo.org/glsa", + original_advisory_text=file, + ) + + def clean_downloads(self): + if self.vcs_response: + self.log("Removing cloned repository") + self.vcs_response.delete() + + def on_failure(self): + self.clean_downloads() + + @staticmethod + def cves_from_reference(reference): + cves = [] + for child in reference: + txt = child.text.strip() + match = re.match(r"CVE-\d{4}-\d{4,}", txt) + if match: + cves.append(match.group()) + return cves + + +def extract_purls_and_constraints(pkg_name, pkg_ns, constraints, invert): + for comparator, version, slot_value in constraints: + qualifiers = {"slot": slot_value} if slot_value else {} + purl = PackageURL(type="ebuild", name=pkg_name, namespace=pkg_ns, qualifiers=qualifiers) + + try: + constraint = VersionConstraint(version=GentooVersion(version), comparator=comparator) + + if invert: + constraint = constraint.invert() + + yield purl, constraint + except InvalidVersion as e: + logger.error(f"InvalidVersion constraints version: {version} error:{e}") + + +def get_affected_and_safe_purls(affected_elem): + for pkg in affected_elem: + name = pkg.attrib.get("name") + if not name: + continue + pkg_ns, _, pkg_name = name.rpartition("/") + + safe_constraints, affected_constraints = get_safe_and_affected_constraints(pkg) + + yield from extract_purls_and_constraints( + pkg_name, pkg_ns, affected_constraints, invert=False + ) + yield from extract_purls_and_constraints(pkg_name, pkg_ns, safe_constraints, invert=True) + + +def get_safe_and_affected_constraints(pkg): + # TODO : Revisit why we are skipping some versions in gentoo importer + skip_versions = {"1.3*", "7.3*", "7.4*"} + safe_versions = set() + affected_versions = set() + for info in pkg: + if info.text in skip_versions: + continue + + # All possible values of info.attrib['range'] = + # {'gt', 'lt', 'rle', 'rge', 'rgt', 'le', 'ge', 'eq'}, out of + # which ('rle', 'rge', 'rgt') are ignored, because they compare + # 'release' not the 'version'. + range_value = info.attrib.get("range") + slot_value = info.attrib.get("slot") + comparator_dict = {"gt": ">", "lt": "<", "ge": ">=", "le": "<=", "eq": "="} + comparator = comparator_dict.get(range_value) + if not comparator: + continue + + if info.tag == "unaffected": + safe_versions.add((comparator, info.text, slot_value)) + + elif info.tag == "vulnerable": + affected_versions.add((comparator, info.text, slot_value)) + return safe_versions, affected_versions diff --git a/vulnerabilities/tests/pipelines/v2_importers/test_gentoo_importer_v2.py b/vulnerabilities/tests/pipelines/v2_importers/test_gentoo_importer_v2.py new file mode 100644 index 000000000..796a87e1a --- /dev/null +++ b/vulnerabilities/tests/pipelines/v2_importers/test_gentoo_importer_v2.py @@ -0,0 +1,41 @@ +# +# Copyright (c) nexB Inc. and others. All rights reserved. +# VulnerableCode is a trademark of nexB Inc. +# SPDX-License-Identifier: Apache-2.0 +# See http://www.apache.org/licenses/LICENSE-2.0 for the license text. +# See https://github.com/aboutcode-org/vulnerablecode for support or download. +# See https://aboutcode.org for more information about nexB OSS projects. +# +import json +from pathlib import Path +from unittest.mock import Mock +from unittest.mock import patch + +import pytest + +from vulnerabilities.pipelines.v2_importers.gentoo_importer import GentooImporterPipeline +from vulnerabilities.tests import util_tests + +TEST_DATA = Path(__file__).parent.parent.parent / "test_data" / "gentoo_v2" + +TEST_CVE_FILES = [ + TEST_DATA / "glsa-201709-09.xml", + TEST_DATA / "glsa-202511-02.xml", + TEST_DATA / "glsa-202512-01.xml", +] + + +@pytest.mark.django_db +@pytest.mark.parametrize("xml_file", TEST_CVE_FILES) +def test_gentoo_advisories_per_file(xml_file): + pipeline = GentooImporterPipeline() + pipeline.vcs_response = Mock(dest_dir=TEST_DATA) + + with patch.object(Path, "glob", return_value=[xml_file]): + results = [adv.to_dict() for adv in pipeline.collect_advisories()] + + for adv in results: + adv["affected_packages"].sort(key=lambda x: json.dumps(x, sort_keys=True)) + + expected_file = xml_file.with_name(xml_file.stem + "-expected.json") + util_tests.check_results_against_json(results, expected_file) diff --git a/vulnerabilities/tests/test_data/gentoo_v2/glsa-201709-09-expected.json b/vulnerabilities/tests/test_data/gentoo_v2/glsa-201709-09-expected.json new file mode 100644 index 000000000..f076423cf --- /dev/null +++ b/vulnerabilities/tests/test_data/gentoo_v2/glsa-201709-09-expected.json @@ -0,0 +1,57 @@ +[ + { + "advisory_id": "GLSA-201709-09", + "aliases": [ + "CVE-2017-9800" + ], + "summary": "A command injection vulnerability in Subversion may allow remote\n attackers to execute arbitrary code.", + "affected_packages": [ + { + "package": { + "type": "ebuild", + "namespace": "dev-vcs", + "name": "subversion", + "version": "", + "qualifiers": "", + "subpath": "" + }, + "affected_version_range": "vers:ebuild/0.1.1", + "fixed_version_range": null, + "introduced_by_commit_patches": [], + "fixed_by_commit_patches": [] + }, + { + "package": { + "type": "ebuild", + "namespace": "dev-vcs", + "name": "subversion", + "version": "", + "qualifiers": "", + "subpath": "" + }, + "affected_version_range": "vers:ebuild/<1.9.7", + "fixed_version_range": null, + "introduced_by_commit_patches": [], + "fixed_by_commit_patches": [] + } + ], + "references_v2": [ + { + "reference_id": "GLSA-201709-09", + "reference_type": "", + "url": "https://security.gentoo.org/glsa/201709-09" + } + ], + "patches": [], + "severities": [ + { + "system": "generic_textual", + "value": "normal", + "scoring_elements": "" + } + ], + "date_published": null, + "weaknesses": [], + "url": "https://security.gentoo.org/glsa/201709-09" + } +] \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/gentoo_v2/glsa-201709-09.xml b/vulnerabilities/tests/test_data/gentoo_v2/glsa-201709-09.xml new file mode 100644 index 000000000..728e6898d --- /dev/null +++ b/vulnerabilities/tests/test_data/gentoo_v2/glsa-201709-09.xml @@ -0,0 +1,77 @@ + + + + Subversion: Arbitrary code execution + A command injection vulnerability in Subversion may allow remote + attackers to execute arbitrary code. + + subversion + 2017-09-17 + 2017-09-17 + 627480 + remote + + + 1.9.7 + 1.8.18 + 1.9.7 + 0.1.1 + + + + +

Subversion is a version control system intended to eventually replace + CVS. Like CVS, it has an optional client-server architecture (where the + server can be an Apache server running mod_svn, or an ssh program as in + CVS’s :ext: method). In addition to supporting the features found in + CVS, Subversion also provides support for moving and copying files and + directories. +

+
+ +

Specially crafted ‘ssh://...’ URLs may allow the owner of the + repository to execute arbitrary commands on client’s machine if those + commands are already installed on the client’s system. This is + especially dangerous when the third-party repository has one or more + submodules with specially crafted ‘ssh://...’ URLs. Each time the + repository is recursively cloned or submodules are updated the payload + will be triggered. +

+
+ +

A remote attacker, by enticing a user to clone a specially crafted + repository, could possibly execute arbitrary code with the privileges of + the process. +

+
+ +

There are several alternative ways to fix this vulnerability. Please + refer to Subversion Team Announce for more details. +

+
+ +

All Subversion 1.9.x users should upgrade to the latest version:

+ + + # emerge --sync + # emerge --ask --oneshot --verbose ">=dev-vcs/subversion-1.9.7" + + +

All Subversion 1.8.x users should upgrade to the latest version:

+ + + # emerge --sync + # emerge --ask --oneshot --verbose ">=dev-vcs/subversion-1.8.18" + +
+ + + CVE-2017-9800 + + + Subversion Team Announce + + + b-man + chrisadr +
diff --git a/vulnerabilities/tests/test_data/gentoo_v2/glsa-202511-02-expected.json b/vulnerabilities/tests/test_data/gentoo_v2/glsa-202511-02-expected.json new file mode 100644 index 000000000..2337fa9b0 --- /dev/null +++ b/vulnerabilities/tests/test_data/gentoo_v2/glsa-202511-02-expected.json @@ -0,0 +1,81 @@ +[ + { + "advisory_id": "GLSA-202511-02", + "aliases": [ + "CVE-2024-40857", + "CVE-2024-40866", + "CVE-2024-44185", + "CVE-2024-44187", + "CVE-2024-44192", + "CVE-2024-44244", + "CVE-2024-44296", + "CVE-2024-54467", + "CVE-2024-54551", + "CVE-2025-24201", + "CVE-2025-24208", + "CVE-2025-24209", + "CVE-2025-24213", + "CVE-2025-24216", + "CVE-2025-24264", + "CVE-2025-30427", + "CVE-2025-31273", + "CVE-2025-31278", + "CVE-2025-43211", + "CVE-2025-43212", + "CVE-2025-43216", + "CVE-2025-43227", + "CVE-2025-43228", + "CVE-2025-43240", + "CVE-2025-43265" + ], + "summary": "Multiple vulnerabilities have been discovered in WebKitGTK+, the worst of which can lead to execution of arbitary code.", + "affected_packages": [ + { + "package": { + "type": "ebuild", + "namespace": "net-libs", + "name": "webkit-gtk", + "version": "", + "qualifiers": "slot=4.1", + "subpath": "" + }, + "affected_version_range": "vers:ebuild/<2.48.5", + "fixed_version_range": null, + "introduced_by_commit_patches": [], + "fixed_by_commit_patches": [] + }, + { + "package": { + "type": "ebuild", + "namespace": "net-libs", + "name": "webkit-gtk", + "version": "", + "qualifiers": "slot=6", + "subpath": "" + }, + "affected_version_range": "vers:ebuild/<2.48.5", + "fixed_version_range": null, + "introduced_by_commit_patches": [], + "fixed_by_commit_patches": [] + } + ], + "references_v2": [ + { + "reference_id": "GLSA-202511-02", + "reference_type": "", + "url": "https://security.gentoo.org/glsa/202511-02" + } + ], + "patches": [], + "severities": [ + { + "system": "generic_textual", + "value": "high", + "scoring_elements": "" + } + ], + "date_published": null, + "weaknesses": [], + "url": "https://security.gentoo.org/glsa/202511-02" + } +] \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/gentoo_v2/glsa-202511-02.xml b/vulnerabilities/tests/test_data/gentoo_v2/glsa-202511-02.xml new file mode 100644 index 000000000..8f541908a --- /dev/null +++ b/vulnerabilities/tests/test_data/gentoo_v2/glsa-202511-02.xml @@ -0,0 +1,73 @@ + + + + WebKitGTK+: Multiple Vulnerabilities + Multiple vulnerabilities have been discovered in WebKitGTK+, the worst of which can lead to execution of arbitary code. + webkit-gtk + 2025-11-24 + 2025-11-24 + 938026 + 941276 + 951739 + 961021 + remote + + + 2.48.5 + 2.48.5 + 2.48.5 + 2.48.5 + + + +

WebKitGTK+ is a full-featured port of the WebKit rendering engine, suitable for projects requiring any kind of web integration, from hybrid HTML/CSS applications to full-fledged web browsers.

+
+ +

Multiple vulnerabilities have been discovered in WebKitGTK+. Please review the CVE identifiers referenced below for details.

+
+ +

Please review the referenced CVE identifiers for details.

+
+ +

There is no known workaround at this time.

+
+ +

All WebKitGTK+ users should upgrade to the latest version:

+ + + # emerge --sync + # emerge --ask --oneshot --verbose ">=net-libs/webkit-gtk-2.48.5:4.1" ">=net-libs/webkit-gtk-2.48.5:6" + +
+ + CVE-2024-40857 + CVE-2024-40866 + CVE-2024-44185 + CVE-2024-44187 + CVE-2024-44192 + CVE-2024-44244 + CVE-2024-44296 + CVE-2024-54467 + CVE-2024-54551 + CVE-2025-24201 + CVE-2025-24208 + CVE-2025-24209 + CVE-2025-24213 + CVE-2025-24216 + CVE-2025-24264 + CVE-2025-30427 + CVE-2025-31273 + CVE-2025-31278 + CVE-2025-43211 + CVE-2025-43212 + CVE-2025-43216 + CVE-2025-43227 + CVE-2025-43228 + CVE-2025-43240 + CVE-2025-43265 + WSA-2025-0002 + WSA-2025-0003 + + graaff + sam +
\ No newline at end of file diff --git a/vulnerabilities/tests/test_data/gentoo_v2/glsa-202512-01-expected.json b/vulnerabilities/tests/test_data/gentoo_v2/glsa-202512-01-expected.json new file mode 100644 index 000000000..605ba19d9 --- /dev/null +++ b/vulnerabilities/tests/test_data/gentoo_v2/glsa-202512-01-expected.json @@ -0,0 +1,41 @@ +[ + { + "advisory_id": "GLSA-202512-01", + "aliases": [], + "summary": "A vulnerability has been discovered in GnuPG, which can lead to arbitrary code execution.", + "affected_packages": [ + { + "package": { + "type": "ebuild", + "namespace": "app-crypt", + "name": "gnupg", + "version": "", + "qualifiers": "", + "subpath": "" + }, + "affected_version_range": "vers:ebuild/<2.5.14", + "fixed_version_range": null, + "introduced_by_commit_patches": [], + "fixed_by_commit_patches": [] + } + ], + "references_v2": [ + { + "reference_id": "GLSA-202512-01", + "reference_type": "", + "url": "https://security.gentoo.org/glsa/202512-01" + } + ], + "patches": [], + "severities": [ + { + "system": "generic_textual", + "value": "high", + "scoring_elements": "" + } + ], + "date_published": null, + "weaknesses": [], + "url": "https://security.gentoo.org/glsa/202512-01" + } +] \ No newline at end of file diff --git a/vulnerabilities/tests/test_data/gentoo_v2/glsa-202512-01.xml b/vulnerabilities/tests/test_data/gentoo_v2/glsa-202512-01.xml new file mode 100644 index 000000000..d4a6b6b9d --- /dev/null +++ b/vulnerabilities/tests/test_data/gentoo_v2/glsa-202512-01.xml @@ -0,0 +1,41 @@ + + + + GnuPG: Arbitrary Code Execution + A vulnerability has been discovered in GnuPG, which can lead to arbitrary code execution. + gnupg + 2025-12-27 + 2025-12-27 + 967884 + remote + + + 2.5.14 + 2.5.14 + + + +

The GNU Privacy Guard, GnuPG, is a free replacement for the PGP suite of cryptographic software.

+
+ +

A vulnerability has been discovered in GnuPG's armor parser.

+
+ +

A remote attacker could entice a user or automated system to process a specially crafted signature file, possibly resulting in execution of arbitrary commands with the privileges of the process.

+
+ +

There is no known workaround at this time.

+
+ +

All GnuPG users should upgrade to the latest version:

+ + + # emerge --sync + # emerge --ask --oneshot --verbose ">=app-crypt/gnupg-2.5.14" + +
+ + + sam + sam +
\ No newline at end of file