Hi Marta,

That's fine, as I said we designed the "ignore" with status "cpe-incorrect" or "ignored" exactly for those purposes. Extending the option with "not affected" doesn't make any sense.

You have to set the status to "why is not affected" = "ignored". Which completely covers the requested case.

Regards,
Andrej

On 25.10.2023 11:33, Marta Rybczynska wrote:
Hi Andrej,
This is more complex. "Not affected" is also an issue that isn't present in the
code - like when we have a version that has never had the vulnerability.
Those are also currently 'Patched' in cve-check.

This work is in sync with what VEX is doing, is it the use-case
Matsanaga-Shinji?

Regards,
Marta

On Wed, Oct 25, 2023 at 8:44 AM Andrej Valek <[email protected]> wrote:
Hi all,

Do we really need a new "not_affected" state? I guess the ignore state
is exactly designed for those purposes.

Regards,
Andrej

On 25.10.2023 07:13, Matsunaga-Shinji wrote:
CVEs that are currently considered "Patched" are classified into the following 
3 statuses:
1. "Patched"      - means that a patch file that fixed the vulnerability has 
been applied
2. "Not affected" - means that the package version (PV) is not affected by the 
vulnerability
3. "Undecidable"  - means that versions cannot be compared to determine if they 
are affected by the vulnerability

Signed-off-by: Shinji Matsunaga <[email protected]>
Signed-off-by: Shunsuke Tokumoto <[email protected]>
---

Changes for v2:
     - Fix the status "Out of range" to "Not affected"

   meta/classes/cve-check.bbclass | 55 +++++++++++++++++++++++-----------
   1 file changed, 38 insertions(+), 17 deletions(-)

diff --git a/meta/classes/cve-check.bbclass b/meta/classes/cve-check.bbclass
index b55f4299da..502db324df 100644
--- a/meta/classes/cve-check.bbclass
+++ b/meta/classes/cve-check.bbclass
@@ -185,10 +185,10 @@ python do_cve_check () {
                   patched_cves = get_patched_cves(d)
               except FileNotFoundError:
                   bb.fatal("Failure in searching patches")
-            ignored, patched, unpatched, status = check_cves(d, patched_cves)
-            if patched or unpatched or (d.getVar("CVE_CHECK_COVERAGE") == "1" 
and status):
-                cve_data = get_cve_info(d, patched + unpatched + ignored)
-                cve_write_data(d, patched, unpatched, ignored, cve_data, 
status)
+            ignored, patched, unpatched, not_affected, undecidable, status = 
check_cves(d, patched_cves)
+            if patched or unpatched or not_affected or undecidable or 
(d.getVar("CVE_CHECK_COVERAGE") == "1" and status):
+                cve_data = get_cve_info(d, patched + unpatched + ignored + 
not_affected + undecidable)
+                cve_write_data(d, patched, unpatched, ignored, not_affected, 
undecidable, cve_data, status)
           else:
               bb.note("No CVE database found, skipping CVE check")

@@ -308,13 +308,13 @@ def check_cves(d, patched_cves):
       products = d.getVar("CVE_PRODUCT").split()
       # If this has been unset then we're not scanning for CVEs here (for 
example, image recipes)
       if not products:
-        return ([], [], [], [])
+        return ([], [], [], [], [], [])
       pv = d.getVar("CVE_VERSION").split("+git")[0]

       # If the recipe has been skipped/ignored we return empty lists
       if pn in d.getVar("CVE_CHECK_SKIP_RECIPE").split():
           bb.note("Recipe has been skipped by cve-check")
-        return ([], [], [], [])
+        return ([], [], [], [], [], [])

       # Convert CVE_STATUS into ignored CVEs and check validity
       cve_ignore = []
@@ -328,6 +328,8 @@ def check_cves(d, patched_cves):
       conn = sqlite3.connect(db_file, uri=True)

       # For each of the known product names (e.g. curl has CPEs using curl and 
libcurl)...
+    cves_not_affected = []
+    cves_undecidable = []
       for product in products:
           cves_in_product = False
           if ":" in product:
@@ -355,6 +357,7 @@ def check_cves(d, patched_cves):

               vulnerable = False
               ignored = False
+            undecidable = False

               product_cursor = conn.execute("SELECT * FROM PRODUCTS WHERE ID IS ? 
AND PRODUCT IS ? AND VENDOR LIKE ?", (cve, product, vendor))
               for row in product_cursor:
@@ -376,7 +379,7 @@ def check_cves(d, patched_cves):
                           except:
                               bb.warn("%s: Failed to compare %s %s %s for %s" %
                                       (product, pv, operator_start, 
version_start, cve))
-                            vulnerable_start = False
+                            undecidable = True
                       else:
                           vulnerable_start = False

@@ -387,10 +390,15 @@ def check_cves(d, patched_cves):
                           except:
                               bb.warn("%s: Failed to compare %s %s %s for %s" %
                                       (product, pv, operator_end, version_end, 
cve))
-                            vulnerable_end = False
+                            undecidable = True
                       else:
                           vulnerable_end = False

+                    if undecidable:
+                        bb.note("%s-%s is undecidable to %s" % (pn, real_pv, 
cve))
+                        cves_undecidable.append(cve)
+                        break
+
                       if operator_start and operator_end:
                           vulnerable = vulnerable_start and vulnerable_end
                       else:
@@ -406,9 +414,9 @@ def check_cves(d, patched_cves):
                       break
               product_cursor.close()

-            if not vulnerable:
+            if not undecidable and not vulnerable:
                   bb.note("%s-%s is not vulnerable to %s" % (pn, real_pv, cve))
-                patched_cves.add(cve)
+                cves_not_affected.append(cve)
           cve_cursor.close()

           if not cves_in_product:
@@ -420,7 +428,7 @@ def check_cves(d, patched_cves):
       if not cves_in_recipe:
           bb.note("No CVE records for products in recipe %s" % (pn))

-    return (list(cves_ignored), list(patched_cves), cves_unpatched, 
cves_status)
+    return (list(cves_ignored), list(patched_cves), cves_unpatched, 
cves_not_affected, cves_undecidable, cves_status)

   def get_cve_info(d, cves):
       """
@@ -447,7 +455,7 @@ def get_cve_info(d, cves):
       conn.close()
       return cve_data

-def cve_write_data_text(d, patched, unpatched, ignored, cve_data):
+def cve_write_data_text(d, patched, unpatched, ignored, not_affected, 
undecidable, cve_data):
       """
       Write CVE information in WORKDIR; and to CVE_CHECK_DIR, and
       CVE manifest if enabled.
@@ -471,7 +479,7 @@ def cve_write_data_text(d, patched, unpatched, ignored, 
cve_data):
           return

       # Early exit, the text format does not report packages without CVEs
-    if not patched+unpatched+ignored:
+    if not patched+unpatched+ignored+not_affected+undecidable:
           return

       nvd_link = "https://nvd.nist.gov/vuln/detail/";
@@ -482,6 +490,8 @@ def cve_write_data_text(d, patched, unpatched, ignored, 
cve_data):
       for cve in sorted(cve_data):
           is_patched = cve in patched
           is_ignored = cve in ignored
+        is_not_affected = cve in not_affected
+        is_undecidable = cve in undecidable

           status = "Unpatched"
           if (is_patched or is_ignored) and not report_all:
@@ -490,6 +500,10 @@ def cve_write_data_text(d, patched, unpatched, ignored, 
cve_data):
               status = "Ignored"
           elif is_patched:
               status = "Patched"
+        elif is_not_affected:
+            status = "Not affected"
+        elif is_undecidable:
+            status = "Undecidable"
           else:
               # default value of status is Unpatched
               unpatched_cves.append(cve)
@@ -561,7 +575,7 @@ def cve_check_write_json_output(d, output, direct_file, 
deploy_file, manifest_fi
           with open(index_path, "a+") as f:
               f.write("%s\n" % fragment_path)

-def cve_write_data_json(d, patched, unpatched, ignored, cve_data, cve_status):
+def cve_write_data_json(d, patched, unpatched, ignored, not_affected, 
undecidable, cve_data, cve_status):
       """
       Prepare CVE data for the JSON format, then write it.
       """
@@ -606,6 +620,9 @@ def cve_write_data_json(d, patched, unpatched, ignored, 
cve_data, cve_status):
       for cve in sorted(cve_data):
           is_patched = cve in patched
           is_ignored = cve in ignored
+        is_not_affected = cve in not_affected
+        is_undecidable = cve in undecidable
+
           status = "Unpatched"
           if (is_patched or is_ignored) and not report_all:
               continue
@@ -613,6 +630,10 @@ def cve_write_data_json(d, patched, unpatched, ignored, 
cve_data, cve_status):
               status = "Ignored"
           elif is_patched:
               status = "Patched"
+        elif is_not_affected:
+            status = "Not affected"
+        elif is_undecidable:
+            status = "Undecidable"
           else:
               # default value of status is Unpatched
               unpatched_cves.append(cve)
@@ -645,12 +666,12 @@ def cve_write_data_json(d, patched, unpatched, ignored, 
cve_data, cve_status):

       cve_check_write_json_output(d, output, direct_file, deploy_file, 
manifest_file)

-def cve_write_data(d, patched, unpatched, ignored, cve_data, status):
+def cve_write_data(d, patched, unpatched, ignored, not_affected, undecidable, 
cve_data, status):
       """
       Write CVE data in each enabled format.
       """

       if d.getVar("CVE_CHECK_FORMAT_TEXT") == "1":
-        cve_write_data_text(d, patched, unpatched, ignored, cve_data)
+        cve_write_data_text(d, patched, unpatched, ignored, not_affected, 
undecidable, cve_data)
       if d.getVar("CVE_CHECK_FORMAT_JSON") == "1":
-        cve_write_data_json(d, patched, unpatched, ignored, cve_data, status)
+        cve_write_data_json(d, patched, unpatched, ignored, not_affected, 
undecidable, cve_data, status)




-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#189674): 
https://lists.openembedded.org/g/openembedded-core/message/189674
Mute This Topic: https://lists.openembedded.org/mt/102172913/21656
Group Owner: [email protected]
Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub 
[[email protected]]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to