A rootfs post command function vuln_cve_make_manifests() generates some manifests about CVE_REPORTS list variable where files are generated in per package task. A vuln_cve_make_manifests() gather these files about installed packages in image from sstate directory to deploy manifest files specified in CVE_MANIFEST to CVE_MANIFEST_DIR.
If CVE_MANIFEST_POPULATES is valid, vuln_cve_make_manifests() populate manifest with "No vulnerability task support packages" which are installed but not inherit vuln-cve and populate package contents with name, version and installed package names. And for the image recipe itself, prepare VULNFUNC_IMAGE_CLASS plugin which may append summary header as image manifest such as CVE database freshness which is inserted at the top of manifest files. Signed-off-by: Toshikazu Nakayama <[email protected]> --- meta/classes/vuln-cve.bbclass | 18 +++++- meta/classes/vuln-cve_image.bbclass | 111 ++++++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 meta/classes/vuln-cve_image.bbclass diff --git a/meta/classes/vuln-cve.bbclass b/meta/classes/vuln-cve.bbclass index 0c7b78c..f916aa8 100644 --- a/meta/classes/vuln-cve.bbclass +++ b/meta/classes/vuln-cve.bbclass @@ -171,12 +171,24 @@ VULNFUNC_JUDGE_CVE = 'list' VULNFUNC_JUDGE_CVE = "" VULNFUNC_REPORT_CVE[type] = 'list' VULNFUNC_REPORT_CVE = "" +VULNFUNC_IMAGE_CLASS[type] = 'list' +VULNFUNC_IMAGE_CLASS = "" python do_vulnerability() { + g = globals() + manifest = d.getVar('CVE_MANIFEST_DIR', True) + if manifest: + # inherit vuln-cve_image from image recipe + image = d.getVar('IMAGE_BASENAME', True) + destdir = os.path.join(d.getVar('VULNSTATEDIR', True), image) + bb.utils.mkdirhier(destdir) + for func in d.getVar('VULNFUNC_IMAGE_CLASS', True).split() or "": + if func in g: + g[func](d, destdir) + return + pn = d.getVar('PN', True) destdir = os.path.join(d.getVar('VULNSTATEDIR', True), pn) bb.utils.mkdirhier(destdir) - g = globals() - cvelist = [] # Gather potential CVE list by using CPE matching for scan in (d.getVar('VULNFUNC_SCAN_CVE', True) or "").split(): @@ -272,6 +284,8 @@ do_vulnerability[sstate-outputdirs] = "${VULN_CVE_DIRECTORY}" do_vulnerability[dir] = "${VULNSTATEDIR}/${PN}" do_vulnerability[cleandirs] = "${VULNSTATEDIR}" do_vulnerability[nostamp] = "1" +# Raising for global "INHERIT += vuln-cve" variable usage. +IMAGE_CLASSES_append = " vuln-cve_image" python do_vulnerability_setscene() { sstate_setscene(d) diff --git a/meta/classes/vuln-cve_image.bbclass b/meta/classes/vuln-cve_image.bbclass new file mode 100644 index 0000000..46cfdb3 --- /dev/null +++ b/meta/classes/vuln-cve_image.bbclass @@ -0,0 +1,111 @@ +# This class deploy CVE manifest for installed packages in rootfs +CVE_REPORTS[type] = 'list' +CVE_CREATE_MANIFEST ??= "1" +CVE_REPORTS ?= "cve.summary cve.patchlist" +CVE_MANIFEST[cve.summary] = "${IMAGE_NAME}${IMAGE_NAME_SUFFIX}.cve.sumary" +CVE_MANIFEST[cve.patchlist] = "${IMAGE_NAME}${IMAGE_NAME_SUFFIX}.cve.patchlist" +CVE_MANIFEST_DIR ?= "${DEPLOY_DIR_IMAGE}" +CVE_MANIFEST_POPULATES ??= "" + +# If image build without INHERIT usage but inherit vuln-cve_image in recipe. +inherit vuln-cve +python vuln_cve_make_manifests() { + vulnstatedir = d.getVar('VULN_CVE_DIRECTORY', True) + destdir = d.getVar('CVE_MANIFEST_DIR', True) + bb.utils.mkdirhier(destdir) + + from oe.rootfs import image_list_installed_packages + pkg_type = d.getVar('PACKAGE_CLASSES', True).replace("package_", "").split()[0] + pkg_dic = {} + notask = [] + def is_notask(sstatedir): + if not os.path.exists(sstatedir): + return True + try: + import time + from datetime import datetime + elapsed = time.time() - os.path.getctime(sstatedir) + if elapsed >= 5 * 60 * 60: + # If package quit to inherit vuln-cve but not cleansstate yet, + # rootfs task can not detect it immediately. + # As results, manifest includes such package unfortunately. + # + # If sstate-dir stamp elapsed more than 5 hours from created, + # forced clean sstate-dir to exclude it from manifest. + bb.warn("%s got staled about vulnerability sstate, " + "force to exclude from manifest" % pn) + bb.utils.remove(sstatedir, recurse=True) + return True + except OSError: + pass + return False + + for pkg in image_list_installed_packages(d): + pkg_info = os.path.join(d.getVar('PKGDATA_DIR', True), + 'runtime-reverse', pkg) + pkgdata = oe.packagedata.read_pkgdatafile(pkg_info) + pkg_name = os.path.basename(os.readlink(pkg_info)) + pn = pkgdata['PN'] + if is_notask(os.path.join(vulnstatedir, pn)): + if not pn in notask: + notask.append(pn) + continue + elif pn in pkg_dic: + if pkg_name in pkg_dic[pn][pkg_type]: + continue + pkg_dic[pn][pkg_type].append(pkg_name) + continue + pkg_dic[pn] = {} + pkg_dic[pn]['pv'] = pkgdata['PV'] + pkg_dic[pn][pkg_type] = [ pkg_name ] + pkg_dic[pn]['ssdir'] = os.path.join(vulnstatedir, pn) + + from datetime import datetime + time_now = "%s" % datetime.now() + image = d.getVar('IMAGE_BASENAME', True) + image_sstate = os.path.join(vulnstatedir, image) + link_name = d.getVar("IMAGE_LINK_NAME") + do_populates = d.getVar('CVE_MANIFEST_POPULATES', True) + for rep in d.getVar('CVE_REPORTS', True).split(): + manifest = d.getVarFlag('CVE_MANIFEST', rep, True) + manifest = os.path.join(destdir, manifest) + manifest_link = os.path.join(destdir, "%s.%s" % (link_name, rep)) + if os.path.exists(os.path.realpath(manifest_link)): + bb.utils.remove(os.path.realpath(manifest_link)) + bb.utils.remove(manifest_link) + # Header for this image + desc = [] + if (os.path.exists(os.path.join(image_sstate, rep))): + # Insert private header if prepared for this manifest. + with open(os.path.join(image_sstate, rep), "r") as r: + desc.append(r.read()) + else: + desc.append("%s: generated at %s\n" % (image, time_now)) + if do_populates and len(notask) > 0: + notask = sorted(notask) + desc.append("\n") + desc.append("No vulnerability task support packages\n") + import textwrap + excludes = textwrap.wrap("[%s]" % ', '.join(notask), 76) + desc.append(" %s\n" % '\n '.join(excludes)) + with open(manifest, 'w') as m: + m.write("%s\n" % ''.join(desc)) + desc.clear() + for pn in sorted(pkg_dic): + write_msg = "" + if do_populates: + write_msg += "%s <%s> %s(%s)\n" % (pn, pkg_dic[pn]['pv'], pkg_type, + ', '.join(pkg_dic[pn][pkg_type])) + if os.path.exists(os.path.join(pkg_dic[pn]['ssdir'], rep)): + with open(os.path.join(pkg_dic[pn]['ssdir'], rep), "r") as r: + write_msg += r.read() + if not write_msg: + continue + desc.append(write_msg) + with open(manifest, 'a') as m: + m.write("%s" % '\n'.join(desc)) + os.symlink(os.path.basename(manifest), manifest_link) + bb.plain("Image CVE report (%s) stored in: %s" % (rep, manifest)) +} +ROOTFS_POSTPROCESS_COMMAND_prepend = "${@'vuln_cve_make_manifests; ' if d.getVar('CVE_CREATE_MANIFEST') == '1' else ''}" +do_rootfs[recrdeptask] += "${@'do_vulnerability' if d.getVar('CVE_CREATE_MANIFEST') == '1' else ''}" -- 2.7.4 -- _______________________________________________ Openembedded-core mailing list [email protected] http://lists.openembedded.org/mailman/listinfo/openembedded-core
