Ejemplo n.º 1
0
def vulnerabilities_for_image(image_obj):
    """
    Return the list of vulnerabilities for the specified image id by recalculating the matches for the image. Ignores
    any persisted matches. Query only, does not update the data. Caller must add returned results to a db session and commit
    in order to persist.

    :param image_obj: the image
    :return: list of ImagePackageVulnerability records for the packages in the given image
    """

    # Recompute. Session and persistence in the session is up to the caller
    try:
        computed_vulnerabilties = []
        for package in image_obj.packages:
            pkg_vulnerabilities = vulnerabilities_for_package(package)
            for v in pkg_vulnerabilities:
                img_v = ImagePackageVulnerability()
                img_v.pkg_image_id = image_obj.id
                img_v.pkg_user_id = image_obj.user_id
                img_v.pkg_name = package.name
                img_v.pkg_type = package.pkg_type
                img_v.pkg_arch = package.arch
                img_v.pkg_version = package.version
                img_v.vulnerability_id = v.vulnerability_id
                img_v.vulnerability_namespace_name = v.namespace_name
                computed_vulnerabilties.append(img_v)
        return computed_vulnerabilties
    except Exception as e:
        log.exception(
            'Error computing full vulnerability set for image {}/{}'.format(
                image_obj.user_id, image_obj.id))
        raise
Ejemplo n.º 2
0
def get_vulnerable_packages(vulnerability_list):
    """
    Run the pipeline for updating image vulnerabilities on the specified list of new/updated/removed records.

    :param vulnerability_list: a list of vulnerability update events
    :return: list of image ids that were modified
    """

    vulnerability_events_by_namespace = {}
    affected = []

    for event in vulnerability_list:
        if event['namespace'] not in vulnerability_events_by_namespace:
            vulnerability_events_by_namespace[event['namespace']] = []

        vulnerability_events_by_namespace[event['namespace']].append(event)

    db = get_thread_scoped_session()
    for namespace, vulns in vulnerability_events_by_namespace.items():
        for vuln in vulns:
            packages = find_vulnerable_image_packages(vuln)
            for pkg in packages:
                img_pkg_v = ImagePackageVulnerability.from_pair(pkg, vuln)
                img_pkg_v = db.merge(img_pkg_v)
                affected.append(img_pkg_v)

    return affected
Ejemplo n.º 3
0
def process_updated_vulnerability(db, vulnerability):
    """
    Update vulnerability matches for this vulnerability. This function will add objects to the db session but
    will not commit. The caller is expected to manage the session lifecycle.

    :param: item: The updated vulnerability object
    :param: db: The db session to use, should be valid and open
    :return: list of (user_id, image_id) that were affected
    """
    log.spew('Processing CVE update for: {}'.format(vulnerability.id))
    changed_images = []

    # Find any packages already matched with the CVE ID.
    current_affected = vulnerability.current_package_vulnerabilities(db)

    # May need to remove vuln from some packages.
    if vulnerability.is_empty():
        log.spew('Detected an empty CVE. Removing all existing matches on this CVE')

        # This is a flush, nothing can be vulnerable to this, so remove it from packages.
        if current_affected:
            log.debug('Detected {} existing matches on CVE {} to remove'.format(len(current_affected), vulnerability.id))

            for pkgVuln in current_affected:
                log.debug('Removing match on image: {}/{}'.format(pkgVuln.pkg_user_id, pkgVuln.pkg_image_id))
                db.delete(pkgVuln)
                changed_images.append((pkgVuln.pkg_user_id, pkgVuln.pkg_image_id))
    else:
        # Find impacted images for the current vulnerability
        new_vulnerable_packages = [ImagePackageVulnerability.from_pair(x, vulnerability) for x in find_vulnerable_image_packages(vulnerability)]
        unique_vuln_pkgs = set(new_vulnerable_packages)
        current_match = set(current_affected)

        if len(new_vulnerable_packages) > 0:
            log.debug('Found {} packages vulnerable to cve {}'.format(len(new_vulnerable_packages), vulnerability.id))
            log.debug('Dedup matches from {} to {}'.format(len(new_vulnerable_packages), len(unique_vuln_pkgs)))

        # Find the diffs of any packages that were vulnerable but are no longer.
        no_longer_affected = current_match.difference(unique_vuln_pkgs)
        possibly_updated = current_match.intersection(unique_vuln_pkgs)
        new_matches = unique_vuln_pkgs.difference(current_match)

        if len(no_longer_affected) > 0:
            log.debug('Found {} packages no longer vulnerable to cve {}'.format(len(no_longer_affected), vulnerability.id))
            for img_pkg_vuln in no_longer_affected:
                log.debug('Removing old invalid match for pkg {} on cve {}'.format(img_pkg_vuln, vulnerability.id))
                db.delete(img_pkg_vuln)
            db.flush()

        for v in new_matches:
            log.debug('Adding new vulnerability match: {}'.format(v))
            db.add(v)
            changed_images.append((v.pkg_user_id, v.pkg_image_id))

        db.flush()

    log.spew('Images changed for cve {}: {}'.format(vulnerability.id, changed_images))

    return changed_images
Ejemplo n.º 4
0
    def test_cmp(self):
        c1 = ImagePackageVulnerability()
        c1.pkg_name = 'testpkg1'
        c1.pkg_version = '1.0'
        c1.pkg_arch = 'x86'
        c1.pkg_type = 'rpm'
        c1.pkg_image_id = 'image123'
        c1.pkg_user_id = '0'
        c1.vulnerability_namespace_name = 'centos:6'
        c1.vulnerability_id = 'CVE-2016-123'
        c1.created_at = datetime.datetime.utcnow()

        c2 = copy.deepcopy(c1)
        self.assertEqual(c1, c2)
        c3 = copy.deepcopy(c1)
        self.assertEqual(c1, c3)
        c4 = copy.deepcopy(c1)
        self.assertEqual(c1, c4)

        c3.pkg_version = '1.1'
        c4.pkg_user_id = '1'

        self.assertEqual(c1, c2)
        self.assertNotEqual(c1, c4)
        self.assertNotEqual(c1, c3)
        self.assertListEqual(list({c1, c2, c3}), list({c1, c3}))

        print('Set: {}'.format({c1, c2, c3}))
Ejemplo n.º 5
0
def test_cmp():
    c1 = ImagePackageVulnerability()
    c1.pkg_name = "testpkg1"
    c1.pkg_version = "1.0"
    c1.pkg_arch = "x86"
    c1.pkg_type = "rpm"
    c1.pkg_image_id = "image123"
    c1.pkg_user_id = "0"
    c1.vulnerability_namespace_name = "centos:6"
    c1.vulnerability_id = "CVE-2016-123"
    c1.created_at = datetime.datetime.utcnow()

    c2 = copy.deepcopy(c1)
    assert c1 == c2
    c3 = copy.deepcopy(c1)
    assert c1 == c3
    c4 = copy.deepcopy(c1)
    assert c1 == c4

    c3.pkg_version = "1.1"
    c4.pkg_user_id = "1"

    assert c1 == c2
    assert c1 != c4
    assert c1 != c3
    assert list({c1, c2, c3}) == list({c1, c3})

    logger.info("Set: {}".format({c1, c2, c3}))
Ejemplo n.º 6
0
def test_cmp():
    c1 = ImagePackageVulnerability()
    c1.pkg_name = 'testpkg1'
    c1.pkg_version = '1.0'
    c1.pkg_arch = 'x86'
    c1.pkg_type = 'rpm'
    c1.pkg_image_id = 'image123'
    c1.pkg_user_id = '0'
    c1.vulnerability_namespace_name = 'centos:6'
    c1.vulnerability_id = 'CVE-2016-123'
    c1.created_at = datetime.datetime.utcnow()

    c2 = copy.deepcopy(c1)
    assert c1 == c2
    c3 = copy.deepcopy(c1)
    assert c1 == c3
    c4 = copy.deepcopy(c1)
    assert c1 == c4

    c3.pkg_version = '1.1'
    c4.pkg_user_id = '1'

    assert c1 == c2
    assert c1 != c4
    assert c1 != c3
    assert list({c1, c2, c3}) == list({c1, c3})

    logger.info('Set: {}'.format({c1, c2, c3}))