[Buildroot] [PATCH v3 6/6] support/scripts/pkgstat: add CPE status reporting

Matt Weber matthew.weber at rockwellcollins.com
Mon May 7 20:30:05 UTC 2018


Signed-off-by: Matthew Weber <matthew.weber at rockwellcollins.com>
---
 support/scripts/pkg-stats | 80 ++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 76 insertions(+), 4 deletions(-)

diff --git a/support/scripts/pkg-stats b/support/scripts/pkg-stats
index 144c00c..82057f1 100755
--- a/support/scripts/pkg-stats
+++ b/support/scripts/pkg-stats
@@ -38,6 +38,7 @@ class Package:
     all_licenses = list()
     all_license_files = list()
     all_versions = dict()
+    all_cpe_id = dict()
 
     def __init__(self, name, path):
         self.name = name
@@ -49,6 +50,8 @@ class Package:
         self.patch_count = 0
         self.warnings = 0
         self.current_version = None
+        self.cpe_id = None
+        self.has_cpe = False
 
     def pkgvar(self):
         return self.name.upper().replace("-", "_")
@@ -122,6 +125,22 @@ class Package:
                 self.warnings = int(m.group(1))
                 return
 
+    def set_cpe_info(self, cpe_dict):
+        """
+        Fills in the .has_cpe field
+        """
+        var = self.pkgvar()
+        if var in self.all_cpe_id:
+            self.cpe_id = self.all_cpe_id[var]
+        result = cpe_dict.find(self.cpe_id)
+        if not result:
+            result = cpe_dict.find_partial(cpe_dict.get_cpe_no_version(self.cpe_id))
+            if result:
+                self.has_cpe = "Update"
+            # Unset case for has_cpe is assumed missing/does not exist
+        else:
+            self.has_cpe = cpe_dict.get_nvd_url(self.cpe_id)
+
     def __eq__(self, other):
         return self.path == other.path
 
@@ -260,6 +279,22 @@ def package_init_make_info():
 
         Package.all_versions[pkgvar] = value
 
+    # CPE ID
+    o = subprocess.check_output(["make", "BR2_HAVE_DOT_CONFIG=y",
+                                 "-s", "printvars", "VARS=%_CPE_ID"])
+    for l in o.splitlines():
+        # Get variable name and value
+        pkgvar, value = l.split("=")
+
+        # Strip _CPE_ID
+        pkgvar = pkgvar[:-7]
+
+        if pkgvar == "LINUX":
+            Package.all_cpe_id[pkgvar] = "cpe:2.3:o:" + value + ":*:*:*:*:*:*:*"
+        elif pkgvar == "LINUX_HEADERS":
+            Package.all_cpe_id[pkgvar] = "cpe:2.3:o:" + value + ":*:*:*:*:*:*:*"
+        else:
+            Package.all_cpe_id[pkgvar] = "cpe:2.3:a:" + value + ":*:*:*:*:*:*:*"
 
 def calculate_stats(packages):
     stats = defaultdict(int)
@@ -285,6 +320,12 @@ def calculate_stats(packages):
             stats["hash"] += 1
         else:
             stats["no-hash"] += 1
+        if pkg.has_cpe == "Update":
+            stats["update-cpe"] += 1
+        elif pkg.has_cpe:
+            stats["cpe"] += 1
+        else:
+            stats["no-cpe"] += 1
         stats["patches"] += pkg.patch_count
     return stats
 
@@ -428,6 +469,20 @@ def dump_html_pkg(f, pkg):
     f.write("  <td class=\"%s\">%d</td>\n" %
             (" ".join(td_class), pkg.warnings))
 
+    # CPE Valid
+    td_class = ["centered"]
+    if not pkg.has_cpe:
+        td_class.append("wrong")
+        f.write("  <td class=\"%s\">%s</td>\n" %
+                (" ".join(td_class), boolean_str(pkg.has_cpe)))
+    elif pkg.has_cpe == "Update":
+        td_class.append("wrong")
+        f.write("  <td class=\"%s\">Update</td>\n" %
+                (" ".join(td_class)))
+    else:
+        td_class.append("correct")
+        f.write("  <td class=\"%s\"><a href=\"%s\">%s</a></td>\n" %
+                (" ".join(td_class), pkg.has_cpe, boolean_str(pkg.has_cpe)))
     f.write(" </tr>\n")
 
 
@@ -443,6 +498,7 @@ def dump_html_all_pkgs(f, packages):
 <td class=\"centered\">Hash file</td>
 <td class=\"centered\">Current version</td>
 <td class=\"centered\">Warnings</td>
+<td class=\"centered\">CPE Valid</td>
 </tr>
 """)
     for pkg in sorted(packages):
@@ -469,6 +525,12 @@ def dump_html_stats(f, stats):
             stats["hash"])
     f.write(" <tr><td>Packages not having a hash file</td><td>%s</td></tr>\n" %
             stats["no-hash"])
+    f.write(" <tr><td>Packages having a registered CPE</td><td>%s</td></tr>\n" %
+            stats["cpe"])
+    f.write(" <tr><td>Packages needing CPE update</td><td>%s</td></tr>\n" %
+            stats["update-cpe"])
+    f.write(" <tr><td>Packages missing a registered CPE</td><td>%s</td></tr>\n" %
+            stats["no-cpe"])
     f.write(" <tr><td>Total number of patches</td><td>%s</td></tr>\n" %
             stats["patches"])
     f.write("</table>\n")
@@ -518,6 +580,16 @@ class CPE:
             if cpe['cpe-23:cpe23-item']['@name'] == cpe_str:
                 return cpe['cpe-23:cpe23-item']['@name']
 
+    def get_cpe_no_version(self, cpe):
+        return cpe.split(":")[0]+":"+cpe.split(":")[1]+ \
+               ":"+cpe.split(":")[2]+":"+cpe.split(":")[3]+ \
+               ":"+cpe.split(":")[4]
+
+    def get_nvd_url(self, cpe_str):
+        return "https://nvd.nist.gov/products/cpe/search/results?keyword=" + \
+               urllib2.quote(cpe_str) + \
+               "&status=FINAL&orderBy=CPEURI&namingFormat=2.3"
+
 def get_target_cpe_report(cpe_report_file, cpe_dict):
     report_cpe_exact_match = ""
     report_cpe_needing_update = ""
@@ -530,8 +602,7 @@ def get_target_cpe_report(cpe_report_file, cpe_dict):
             if "CPE ID" not in cpe[0]:
                 result = cpe_dict.find(cpe[0])
                 if not result:
-                    cpe_no_version = cpe[0].split(":")[0]+":"+cpe[0].split(":")[1]+":"+cpe[0].split(":")[2]+":"+cpe[0].split(":")[3]+":"+cpe[0].split(":")[4]
-                    result = cpe_dict.find_partial(cpe_no_version)
+                    result = cpe_dict.find_partial(cpe_dict.get_cpe_no_version(cpe[0]))
                     if not result:
                         report_cpe_missing += cpe[0] + "\n"
                     else:
@@ -569,10 +640,10 @@ def __main__():
         package_list = args.packages.split(",")
     else:
         package_list = None
+    cpe_dict = CPE()
+    cpe_dict.get_xml_dict()
     if args.cpe_report:
         print "Performing Target CPE Report Analysis..."
-        cpe_dict = CPE()
-        cpe_dict.get_xml_dict()
         get_target_cpe_report(args.cpe_report,cpe_dict)
     else:
        print "Build package list ..."
@@ -587,6 +658,7 @@ def __main__():
           pkg.set_patch_count()
           pkg.set_check_package_warnings()
           pkg.set_current_version()
+          pkg.set_cpe_info(cpe_dict)
        print "Calculate stats"
        stats = calculate_stats(packages)
        print "Write HTML"
-- 
1.9.1




More information about the buildroot mailing list