summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeil Williams <codehelp@debian.org>2021-12-20 12:39:20 +0000
committerNeil Williams <codehelp@debian.org>2022-01-27 09:08:15 +0000
commit8cbd0b858ff3c68c949187eaa66a1df960425471 (patch)
tree76f0578f12f825af4de8d7d2f364a3222d92763b
parent686f1876c1def548285687d61ff3b728266c0f77 (diff)
Add remaining support and switch to using logging
Add support to add a bug number. Add warnings in --help that each update must be merged before the same CVE can be updated again.
-rwxr-xr-xbin/update-vuln167
1 files changed, 146 insertions, 21 deletions
diff --git a/bin/update-vuln b/bin/update-vuln
index 9e3d710b5a..e5847baa4b 100755
--- a/bin/update-vuln
+++ b/bin/update-vuln
@@ -28,12 +28,14 @@
import os
import argparse
+import logging
import sys
import setup_paths # noqa # pylint: disable=unused-import
from sectracker.parsers import (
sourcepackages,
PackageAnnotation,
+ PackageBugAnnotation,
StringAnnotation,
Bug,
cvelist,
@@ -50,6 +52,14 @@ class ParseUpdates:
def __init__(self):
self.cves = []
self.bugs = {}
+ self.logger = logging.getLogger("update-vuln")
+ self.logger.setLevel(logging.DEBUG)
+ # console logging
+ ch = logging.StreamHandler()
+ ch.setLevel(logging.DEBUG)
+ formatter = logging.Formatter("%(name)s - %(levelname)s - %(message)s")
+ ch.setFormatter(formatter)
+ self.logger.addHandler(ch)
def _read_cvelist(self):
os.chdir(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
@@ -62,15 +72,13 @@ class ParseUpdates:
def _add_annotation_after_line(self, cve, line, annotation):
bug_list = list(self.bugs[cve].annotations)
bug_list.append(annotation)
- mod_bug = Bug(self.bugs[cve].file, self.bugs[cve].header, tuple(bug_list))
- return mod_bug
+ return Bug(self.bugs[cve].file, self.bugs[cve].header, tuple(bug_list))
def _replace_annotation_on_line(self, cve, line, mod_line):
index = self.bugs[cve].annotations.index(line)
bug_list = list(self.bugs[cve].annotations)
bug_list[index] = mod_line
- mod_bug = Bug(self.bugs[cve].file, self.bugs[cve].header, tuple(bug_list))
- return mod_bug
+ return Bug(self.bugs[cve].file, self.bugs[cve].header, tuple(bug_list))
def write_modified(self, modified, cve_file):
if not modified:
@@ -78,10 +86,13 @@ class ParseUpdates:
if not isinstance(modified, list):
return
if os.path.exists(cve_file):
- raise OSError("%s already exists" % cve_file)
+ self.logger.critical("%s already exists - appending", cve_file)
+ return -1
mods = []
for cve in modified:
- print(f"Writing to ./{cve_file} with update for {cve.header.name}.")
+ self.logger.info(
+ "Writing to ./%s with update for %s", cve_file, cve.header.name
+ )
with open(cve_file, "a") as snippet:
writecvelist(modified, snippet)
@@ -109,16 +120,18 @@ class ParseUpdates:
# need to define the allowed changes
# if fixed, version would need to be undone too.
if line.kind == "not-affected":
- print(f"Nothing to do for {cve} in {suite}.")
+ self.logger.info("Nothing to do for %s in %s.", cve, suite)
return
mod_line = line._replace(kind="not-affected")
- print(f"Modified {cve} for {src} in {release} to <not-affected>")
+ self.logger.info(
+ "Modified %s for %s in %s to <not-affected>", cve, src, release
+ )
if mod_line.version:
- print(f"Removing version {line.version}")
+ self.logger.info("Removing version %s", line.version)
ver_line = mod_line
mod_line = ver_line._replace(version=None)
if mod_line.description:
- print(f"Removing description {line.description}")
+ self.logger.info("Removing description %s", line.description)
desc_line = mod_line
mod_line = desc_line._replace(description=None)
# removing a bug annotation is not covered, yet.
@@ -133,48 +146,160 @@ class ParseUpdates:
Fails if the file already exists.
"""
# use _add_annotation_after_line to add a line
- pass
+ modified = []
+ cve = self.cves[0]
+ cve_file = f"{cve}.list"
+ existing = [
+ note.description
+ for note in self.bugs[cve].annotations
+ if isinstance(note, StringAnnotation)
+ ]
+ lines = [
+ note.line
+ for note in self.bugs[cve].annotations
+ if isinstance(note, StringAnnotation)
+ ]
+ if note in existing:
+ self.logger.info("Note already exists, ignoring")
+ return
+ new_note = StringAnnotation(line=0, type="NOTE", description=note)
+ mod_bug = self._add_annotation_after_line(cve, 0, new_note)
+ modified.append(mod_bug)
+ self.write_modified(modified, cve_file)
- def add_bug_number(self, bug):
+ def add_bug_number(self, bug, itp=False):
"""
Writes out a CVE file snippet with the filename:
./<cve>.list
Fails if the file already exists.
"""
- # need to work out how to manipulate releases
- pass
+ # bugs only apply to unstable (or itp)
+ modified = []
+ cve = self.cves[0]
+ cve_file = f"{cve}.list"
+ existing = [
+ pkg.flags
+ for pkg in self.bugs[cve].annotations
+ if isinstance(pkg, PackageAnnotation)
+ if not pkg.release and pkg.kind != "removed"
+ ]
+ bugs = [bug for sublist in existing for bug in sublist]
+ if bugs:
+ self.logger.warning(
+ "%s already has a bug annotation for unstable: %s", cve, bugs[0].bug
+ )
+ return -1
+ pkgs = [
+ pkg
+ for pkg in self.bugs[cve].annotations
+ if isinstance(pkg, PackageAnnotation)
+ if not pkg.release and pkg.kind != "removed"
+ ]
+ if itp:
+ # no useful entry will exist in pkgs
+ new_flags = [PackageBugAnnotation(bug)]
+ new_pkg = PackageAnnotation(
+ 0,
+ "package",
+ None,
+ itp,
+ "itp",
+ None,
+ None,
+ new_flags,
+ )
+ others = []
+ else:
+ if not pkgs:
+ self.logger.error("%s does not have a package annotation.", cve)
+ return -1
+ old_pkg = pkgs[0]
+ if itp and old_pkg.kind == "fixed":
+ self.logger.error(
+ "%s is already marked as <fixed> but --itp flag was set.", cve
+ )
+ return -3
+ new_flags = [PackageBugAnnotation(bug)]
+ new_pkg = PackageAnnotation(
+ old_pkg.line,
+ old_pkg.type,
+ old_pkg.release,
+ old_pkg.package,
+ old_pkg.kind,
+ old_pkg.version,
+ old_pkg.description,
+ new_flags,
+ )
+ others = [pkg for pkg in bug_list if pkg.line != old_pkg.line]
+ bug_list = list(self.bugs[cve].annotations)
+ # may need to retain the original order.
+ new_list = [new_pkg] + others
+ mod_bug = Bug(self.bugs[cve].file, self.bugs[cve].header, tuple(new_list))
+ modified.append(mod_bug)
+ self.write_modified(modified, cve_file)
def load_cve(self, cve):
- print(f"Loading data for {cve}...")
+ self.logger.info("Loading data for %s...", cve)
self.cves.append(cve)
self._read_cvelist()
def main():
+ """
+ This script does NOT reparse the output file - create, review and
+ merge ONE update at a time.
+ (For some operations, check-new-issues may be more suitable).
+
+ For example, --bug 100 --itp intended_pkg_name
+ then, merge-cve-list, then:
+ --note "URL:"
+ """
parser = argparse.ArgumentParser(
- description="Update a specified CVE data as not-affected, add bug number or add a note",
+ description="Make a single update to specified CVE data as "
+ "not-affected, add bug number or add a note",
epilog="Data is written to a new <cve_number>.list "
- "file which can be used with './bin/merge-cve-files'",
+ "file which can be used with './bin/merge-cve-files'. "
+ "Make sure the output file is merged and removed before "
+ "updating the same CVE again.",
)
+
required = parser.add_argument_group("Required arguments")
required.add_argument("--cve", required=True, help="The CVE ID to update")
- affected = parser.add_argument_group("Marking a CVE as not-affected")
+
+ affected = parser.add_argument_group(
+ "Marking a CVE as not-affected - must use --src and --suite"
+ )
# needs to specify the src_package as well as suite to cope with removed etc.
affected.add_argument("--src", help="Source package name in SUITE")
affected.add_argument(
"--suite", default="unstable", help="Mark the CVE as <not-affected> in SUITE"
)
+
buggy = parser.add_argument_group("Add a bug number to the CVE")
buggy.add_argument("--number", help="Debian BTS bug number")
+ buggy.add_argument(
+ "--itp",
+ metavar="SRC",
+ help="Mark as an ITP bug for the specified source package name",
+ )
+
notes = parser.add_argument_group("Add a NOTE: entry to the CVE")
notes.add_argument("--note", help="Content of the NOTE: entry to add to the CVE")
+
args = parser.parse_args()
parser = ParseUpdates()
parser.load_cve(args.cve)
+
if not parser.bugs:
- raise ValueError("Unable to parse CVE ID %s" % args.cve)
- # print(parser.bugs[args.cve].header.description)
- parser.mark_not_affected(args.suite, args.src)
+ self.logger.critical("Unable to parse CVE ID %s", args.cve)
+ return -1
+ if args.src and args.suite:
+ parser.mark_not_affected(args.suite, args.src)
+ if args.note:
+ parser.add_note(args.note)
+ if args.number:
+ # to set itp properly, the source package name also needs to be set.
+ parser.add_bug_number(args.number, args.itp)
return 0

© 2014-2024 Faster IT GmbH | imprint | privacy policy