From patchwork Mon Dec 16 16:00:04 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Armin Kuster X-Patchwork-Id: 181747 Delivered-To: patch@linaro.org Received: by 2002:ac9:44c4:0:0:0:0:0 with SMTP id t4csp4482463och; Mon, 16 Dec 2019 08:02:38 -0800 (PST) X-Google-Smtp-Source: APXvYqz8xZk1DsN2bcU55HJhfkFHVSfvszS2FPVmKC9sxo0AG/FDqJGvncNuma8usQFVT5WUExow X-Received: by 2002:a63:1101:: with SMTP id g1mr18525077pgl.435.1576512157961; Mon, 16 Dec 2019 08:02:37 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1576512157; cv=none; d=google.com; s=arc-20160816; b=GPDn0e/mg5QEkBAUBfbwfj6vPL2Q2Zx64hpQkQmSfbqHyzVC5IWcSDdf/JWwDENlID qvfHieuKGb/L38MehJxyEFVDkrKshMa164OuLEGOtspAiKxls81vh+VPrdKy3e1er9xF Y72wj8ddnm3NRBXi4TYaXBSjJsRmsqDA5OhLALoiq0ocClzvReRB6Y3O0fFLRqNTPyIe JXnc0G8GTWnJ0NZovlq+pQmNsHB5GQHi/m5AUnpaPb2EOSIy5cZTUw+HdZHADAa7tGQx VvnHdWs9NofDQBRW/vpbAjZ2JxQUVkCOoO5sGv2o5EMPZnulV8scgCdzZWJVP+DkWdRU 8zzw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=errors-to:sender:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:references:in-reply-to:message-id:date :to:from:dkim-signature:delivered-to; bh=m+m0fixajNsYzRP3nAWnJtAt0YPOzjXpAK6xz8eoJfc=; b=hTwCd8BThvezxy8aT/1Lr5lwK0/qf77QAGNyckVf0H5BQz0IStHvjL4T1cFQ/1S/EY s0GBunF35QvIgOVL/ejq1Li9cfgMwQ0LhvbExaqwJKj25EyB/UgS36gK039JOaE2QErj 64IMauwJKQiBAxolrHhmXaTXVv4SwvsimyPkETLPe0Cb/8loX4PKQGzmkeILaUvzUEsJ bCY21MM6v80UrOzQL80GEvImLeIP6/jgXWyJ7wjn6bXTxLjX3jxxnPnX/moBeuU4RaYj gwLmIiXIYFcKvH5bym1HnwVpw+IbnzuEK8kefMCrPR6HVtNQ5mrjX1L2behWK9y9i3Sb bliw== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=PJTuy58o; spf=pass (google.com: best guess record for domain of openembedded-core-bounces@lists.openembedded.org designates 140.211.169.62 as permitted sender) smtp.mailfrom=openembedded-core-bounces@lists.openembedded.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from mail.openembedded.org (mail.openembedded.org. [140.211.169.62]) by mx.google.com with ESMTP id b11si12520765plz.236.2019.12.16.08.02.37; Mon, 16 Dec 2019 08:02:37 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of openembedded-core-bounces@lists.openembedded.org designates 140.211.169.62 as permitted sender) client-ip=140.211.169.62; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=PJTuy58o; spf=pass (google.com: best guess record for domain of openembedded-core-bounces@lists.openembedded.org designates 140.211.169.62 as permitted sender) smtp.mailfrom=openembedded-core-bounces@lists.openembedded.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from ec2-34-214-78-129.us-west-2.compute.amazonaws.com (localhost [127.0.0.1]) by mail.openembedded.org (Postfix) with ESMTP id E8CCC7FE18; Mon, 16 Dec 2019 16:00:49 +0000 (UTC) X-Original-To: openembedded-core@lists.openembedded.org Delivered-To: openembedded-core@lists.openembedded.org Received: from mail-pl1-f177.google.com (mail-pl1-f177.google.com [209.85.214.177]) by mail.openembedded.org (Postfix) with ESMTP id 9EF887FDD1 for ; Mon, 16 Dec 2019 16:00:24 +0000 (UTC) Received: by mail-pl1-f177.google.com with SMTP id x17so4665931pln.1 for ; Mon, 16 Dec 2019 08:00:26 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references; bh=ZFs0MnN/bBfSg/6D+ln1OmgzSOl42k/KJkc0HvAoc1g=; b=PJTuy58ow2S2FE7eIICG33DJUTi+Hsew0X8d2edtyyRGHus5x3+XGwcahXka4qX8RC mMuPp6I985ep267lRanC8YkOgRW0Q3TJXs3f0UWDhpiwI7jFhT/zaR68nZv8U4geWMqN Rlnc3H9OVcdAo9cRyzjgchGT/NHPtiXPuGdpqq06DXEaklcTDCUmNEr/pxkegfBJbo8e GkeeRhTTAAdbZwNcLKmxVert2ABb8oT0K+y9yckqae1SrpNg6a1Or+K8LMbwnR+LWa6r eaqKF2j3GGVSNobOnC3mUXGif3WTmx9oNpCz7G+ySW7DHhYLFjkLgZHt+6K9hMBW19HQ uGGA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=ZFs0MnN/bBfSg/6D+ln1OmgzSOl42k/KJkc0HvAoc1g=; b=qfEC2UAPPdNN0ebM45onWLKR0zIQAgNsGvXzknC9FXl1naSyxxfhKoqyRivN0H4lFp HnPzV2Y8Sx3A+ro0bsvVHN2zNaUy/HdqvsnsvdDBEfJbDOqIHcz0q8YmnfEhHCEXpbVW JcEoDUh5jLA+7AjQFIbOi3Eeu80aJICIPMBZxp2867fSg6Zw42IDPJfaS0yWGP9HiZXo jdqntJa6LP3bv1RO2AN3B97Rsd/03oAXoCHzGZymKpjIZJ1aJ+HaRpb7BaUaoAPJODEP nM+yGtEqBFz1PT3bhaitl+f9nHQwc0BO6TWp7byauo7P2OkIm2JdoKL/kFgVx4fiif3H rI3Q== X-Gm-Message-State: APjAAAWimrhzC1Ir5susdfI5fE4u5ZHlGqTsG9qWl4vcvgA3MRQ/lZc9 QSgQpDNUZmOMBbjJE+0gGiRphDZ8VeM= X-Received: by 2002:a17:902:9b84:: with SMTP id y4mr16175242plp.13.1576512025495; Mon, 16 Dec 2019 08:00:25 -0800 (PST) Received: from akuster-ThinkPad-T460s.mvista.com ([2601:202:4180:a5c0:e5c5:31c9:a010:f145]) by smtp.gmail.com with ESMTPSA id g6sm19568697pjl.25.2019.12.16.08.00.24 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 16 Dec 2019 08:00:24 -0800 (PST) From: Armin Kuster To: openembedded-core@lists.openembedded.org Date: Mon, 16 Dec 2019 08:00:04 -0800 Message-Id: <541dc24d974d3e22c45a650c34298eebc45121e8.1576511913.git.akuster808@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: References: Subject: [OE-core] [thud 14/18] cve-check: rewrite look to fix false negatives X-BeenThere: openembedded-core@lists.openembedded.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: Patches and discussions about the oe-core layer List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: openembedded-core-bounces@lists.openembedded.org Errors-To: openembedded-core-bounces@lists.openembedded.org From: Ross Burton A previous optimisation was premature and resulted in false-negatives in the report. Rewrite the checking algorithm to first get the list of potential CVEs by vendor:product, then iterate through every matching CPE for that CVE to determine if the bounds match or not. By doing this in two stages we can know if we've checked every CPE, instead of accidentally breaking out of the scan too early. (From OE-Core rev: d61aff9e22704ad69df1f7ab0f8784f4e7cc0c69) Signed-off-by: Ross Burton Signed-off-by: Richard Purdie Signed-off-by: Armin Kuster --- meta/classes/cve-check.bbclass | 63 +++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 29 deletions(-) -- 2.7.4 -- _______________________________________________ Openembedded-core mailing list Openembedded-core@lists.openembedded.org http://lists.openembedded.org/mailman/listinfo/openembedded-core diff --git a/meta/classes/cve-check.bbclass b/meta/classes/cve-check.bbclass index 3326944..c1cbdbd 100644 --- a/meta/classes/cve-check.bbclass +++ b/meta/classes/cve-check.bbclass @@ -165,7 +165,6 @@ def check_cves(d, patched_cves): """ Connect to the NVD database and find unpatched cves. """ - import ast, csv, tempfile, subprocess, io from distutils.version import LooseVersion cves_unpatched = [] @@ -187,68 +186,74 @@ def check_cves(d, patched_cves): cve_whitelist = d.getVar("CVE_CHECK_WHITELIST").split() import sqlite3 - db_file = d.getVar("CVE_CHECK_DB_FILE") - conn = sqlite3.connect(db_file) + db_file = d.expand("file:${CVE_CHECK_DB_FILE}?mode=ro") + conn = sqlite3.connect(db_file, uri=True) + # For each of the known product names (e.g. curl has CPEs using curl and libcurl)... for product in products: - c = conn.cursor() if ":" in product: vendor, product = product.split(":", 1) - c.execute("SELECT * FROM PRODUCTS WHERE PRODUCT IS ? AND VENDOR IS ?", (product, vendor)) else: - c.execute("SELECT * FROM PRODUCTS WHERE PRODUCT IS ?", (product,)) + vendor = "%" - for row in c: - cve = row[0] - version_start = row[3] - operator_start = row[4] - version_end = row[5] - operator_end = row[6] + # Find all relevant CVE IDs. + for cverow in conn.execute("SELECT DISTINCT ID FROM PRODUCTS WHERE PRODUCT IS ? AND VENDOR LIKE ?", (product, vendor)): + cve = cverow[0] if cve in cve_whitelist: bb.note("%s-%s has been whitelisted for %s" % (product, pv, cve)) # TODO: this should be in the report as 'whitelisted' patched_cves.add(cve) + continue elif cve in patched_cves: bb.note("%s has been patched" % (cve)) - else: - to_append = False + continue + + vulnerable = False + for row in conn.execute("SELECT * FROM PRODUCTS WHERE ID IS ? AND PRODUCT IS ? AND VENDOR LIKE ?", (cve, product, vendor)): + (_, _, _, version_start, operator_start, version_end, operator_end) = row + #bb.debug(2, "Evaluating row " + str(row)) + if (operator_start == '=' and pv == version_start): - to_append = True + vulnerable = True else: if operator_start: try: - to_append_start = (operator_start == '>=' and LooseVersion(pv) >= LooseVersion(version_start)) - to_append_start |= (operator_start == '>' and LooseVersion(pv) > LooseVersion(version_start)) + vulnerable_start = (operator_start == '>=' and LooseVersion(pv) >= LooseVersion(version_start)) + vulnerable_start |= (operator_start == '>' and LooseVersion(pv) > LooseVersion(version_start)) except: bb.warn("%s: Failed to compare %s %s %s for %s" % (product, pv, operator_start, version_start, cve)) - to_append_start = False + vulnerable_start = False else: - to_append_start = False + vulnerable_start = False if operator_end: try: - to_append_end = (operator_end == '<=' and LooseVersion(pv) <= LooseVersion(version_end)) - to_append_end |= (operator_end == '<' and LooseVersion(pv) < LooseVersion(version_end)) + vulnerable_end = (operator_end == '<=' and LooseVersion(pv) <= LooseVersion(version_end)) + vulnerable_end |= (operator_end == '<' and LooseVersion(pv) < LooseVersion(version_end)) except: bb.warn("%s: Failed to compare %s %s %s for %s" % (product, pv, operator_end, version_end, cve)) - to_append_end = False + vulnerable_end = False else: - to_append_end = False + vulnerable_end = False if operator_start and operator_end: - to_append = to_append_start and to_append_end + vulnerable = vulnerable_start and vulnerable_end else: - to_append = to_append_start or to_append_end + vulnerable = vulnerable_start or vulnerable_end - if to_append: + if vulnerable: bb.note("%s-%s is vulnerable to %s" % (product, pv, cve)) cves_unpatched.append(cve) - else: - bb.note("%s-%s is not vulnerable to %s" % (product, pv, cve)) - patched_cves.add(cve) + break + + if not vulnerable: + bb.note("%s-%s is not vulnerable to %s" % (product, pv, cve)) + # TODO: not patched but not vulnerable + patched_cves.add(cve) + conn.close() return (list(patched_cves), cves_unpatched)