summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeil Williams <codehelp@debian.org>2021-12-17 14:11:48 +0000
committerNeil Williams <codehelp@debian.org>2022-01-27 09:08:15 +0000
commitaa7282b74f0aa3b431fe999397b735125bee624c (patch)
treea876bdb3709abbbcb59f11a0c02a19aa7cefe016
parent1b8cdbe67e1481f4ad9d7a56856deaec8547ede1 (diff)
Add initial update-vuln script
-rwxr-xr-xbin/update-vuln182
1 files changed, 182 insertions, 0 deletions
diff --git a/bin/update-vuln b/bin/update-vuln
new file mode 100755
index 0000000000..9e3d710b5a
--- /dev/null
+++ b/bin/update-vuln
@@ -0,0 +1,182 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+ update-vuln - #1001453
+
+ - mark a given released suite (stable/oldstable/LTS) as <not-affected>
+ for a specific CVE ID
+ - add a bug number to an existing CVE entry
+ - add a NOTE: entry to an existing CVE
+
+"""
+# Copyright 2021 Neil Williams <codehelp@debian.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+import os
+import argparse
+import sys
+
+import setup_paths # noqa # pylint: disable=unused-import
+from sectracker.parsers import (
+ sourcepackages,
+ PackageAnnotation,
+ StringAnnotation,
+ Bug,
+ cvelist,
+ writecvelist,
+)
+
+
+class ParseUpdates:
+ """
+ Update a CVE with requested changes and produce a file for
+ manual review and use with merge-cve-files.
+ """
+
+ def __init__(self):
+ self.cves = []
+ self.bugs = {}
+
+ def _read_cvelist(self):
+ os.chdir(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
+ data, _ = cvelist("data/CVE/list")
+ for cve in self.cves:
+ for bug in data:
+ if bug.header.name == cve:
+ self.bugs[cve] = bug
+
+ 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
+
+ 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
+
+ def write_modified(self, modified, cve_file):
+ if not modified:
+ return
+ if not isinstance(modified, list):
+ return
+ if os.path.exists(cve_file):
+ raise OSError("%s already exists" % cve_file)
+ mods = []
+ for cve in modified:
+ print(f"Writing to ./{cve_file} with update for {cve.header.name}.")
+ with open(cve_file, "a") as snippet:
+ writecvelist(modified, snippet)
+
+ def mark_not_affected(self, suite, src):
+ """
+ Writes out a CVE file snippet with the filename:
+ ./<cve>.list
+ Fails if the file already exists.
+ """
+ release = suite
+ if suite == "unstable" or suite == "sid":
+ # special handling for unstable
+ suite = None
+ release = "unstable"
+ modified = []
+ cve = self.cves[0]
+ cve_file = f"{cve}.list"
+ for line in self.bugs[cve].annotations:
+ if not isinstance(line, PackageAnnotation):
+ continue # skip notes etc.
+ if line.release != suite:
+ continue
+ if line.package != src:
+ continue
+ # 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}.")
+ return
+ mod_line = line._replace(kind="not-affected")
+ print(f"Modified {cve} for {src} in {release} to <not-affected>")
+ if mod_line.version:
+ print(f"Removing version {line.version}")
+ ver_line = mod_line
+ mod_line = ver_line._replace(version=None)
+ if mod_line.description:
+ print(f"Removing description {line.description}")
+ desc_line = mod_line
+ mod_line = desc_line._replace(description=None)
+ # removing a bug annotation is not covered, yet.
+ mod_bug = self._replace_annotation_on_line(cve, line, mod_line)
+ modified.append(mod_bug)
+ self.write_modified(modified, cve_file)
+
+ def add_note(self, note):
+ """
+ Writes out a CVE file snippet with the filename:
+ ./<cve>.list
+ Fails if the file already exists.
+ """
+ # use _add_annotation_after_line to add a line
+ pass
+
+ def add_bug_number(self, bug):
+ """
+ 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
+
+ def load_cve(self, cve):
+ print(f"Loading data for {cve}...")
+ self.cves.append(cve)
+ self._read_cvelist()
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ description="Update a 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'",
+ )
+ 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")
+ # 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")
+ 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)
+ return 0
+
+
+if __name__ == "__main__":
+ sys.exit(main())

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