예제 #1
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
예제 #2
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